feat:个人信息功能修改

This commit is contained in:
fanxb 2021-03-05 17:03:51 +08:00
parent a960ca062f
commit d8c6aefd13
8 changed files with 111 additions and 20 deletions

View File

@ -17,7 +17,7 @@ import javax.validation.constraints.Pattern;
@Data @Data
public class EmailUpdateBody { public class EmailUpdateBody {
@NotNull(message = "参数不为空") @NotNull(message = "参数不为空")
private String actionId; private String oldPassword;
@Email(message = "请输入有效邮箱地址") @Email(message = "请输入有效邮箱地址")
private String email; private String email;
} }

View File

@ -15,7 +15,7 @@ import javax.validation.constraints.Pattern;
@Data @Data
public class UpdatePasswordBody { public class UpdatePasswordBody {
private String actionId; private String oldPassword;
@Pattern(regexp = ValidatedConstant.PASSWORD_REG, message = ValidatedConstant.PASSWORD_MESSAGE) @Pattern(regexp = ValidatedConstant.PASSWORD_REG, message = ValidatedConstant.PASSWORD_MESSAGE)
private String password; private String password;
} }

View File

@ -1,5 +1,6 @@
package com.fanxb.bookmark.business.user.service; package com.fanxb.bookmark.business.user.service;
import cn.hutool.core.util.StrUtil;
import com.fanxb.bookmark.business.user.constant.RedisConstant; import com.fanxb.bookmark.business.user.constant.RedisConstant;
import com.fanxb.bookmark.business.user.dao.UserDao; import com.fanxb.bookmark.business.user.dao.UserDao;
import com.fanxb.bookmark.business.user.entity.EmailUpdateBody; import com.fanxb.bookmark.business.user.entity.EmailUpdateBody;
@ -39,10 +40,9 @@ public class BaseInfoService {
public void changePassword(UpdatePasswordBody body) { public void changePassword(UpdatePasswordBody body) {
int userId = UserContextHolder.get().getUserId(); int userId = UserContextHolder.get().getUserId();
String checkAuthKey = com.fanxb.bookmark.common.constant.RedisConstant.getPasswordCheckKey(userId, body.getActionId()); String password = userDao.selectByUserId(userId).getPassword();
String str = RedisUtil.get(checkAuthKey, String.class); if (!StrUtil.equals(password, HashUtil.getPassword(body.getOldPassword()))) {
if (str == null) { throw new CustomException("旧密码错误");
throw new CustomException("密码校验失败,无法更新密码");
} }
userDao.updatePasswordByUserId(userId, HashUtil.getPassword(body.getPassword())); userDao.updatePasswordByUserId(userId, HashUtil.getPassword(body.getPassword()));
} }
@ -69,12 +69,10 @@ public class BaseInfoService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void updateEmail(EmailUpdateBody body) { public void updateEmail(EmailUpdateBody body) {
int userId = UserContextHolder.get().getUserId(); int userId = UserContextHolder.get().getUserId();
String checkAuthKey = com.fanxb.bookmark.common.constant.RedisConstant.getPasswordCheckKey(userId, body.getActionId()); String oldPassword = userDao.selectByUserId(userId).getPassword();
String str = RedisUtil.get(checkAuthKey, String.class); if (!StrUtil.equals(oldPassword, HashUtil.getPassword(body.getOldPassword()))) {
if (str == null) {
throw new CustomException("密码校验失败无法更新email"); throw new CustomException("密码校验失败无法更新email");
} }
RedisUtil.delete(checkAuthKey);
String secret = UUID.randomUUID().toString().replaceAll("-", ""); String secret = UUID.randomUUID().toString().replaceAll("-", "");
String url = VERIFY_EMAIL.replaceAll("XXXX", Constant.serviceAddress + VERIFY_EMAIL_PATH + secret); String url = VERIFY_EMAIL.replaceAll("XXXX", Constant.serviceAddress + VERIFY_EMAIL_PATH + secret);
log.debug(url); log.debug(url);

View File

@ -3,7 +3,6 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- <meta name="viewport" content="width=device-width,initial-scale=1.0" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title> <title><%= htmlWebpackPlugin.options.title %></title>

View File

@ -1,19 +1,19 @@
<template> <template>
<div class="main"> <div class="main">
<div>bottom</div> <div>开源地址:<a href="https://github.com/FleyX/bookmark">github.com/FleyX/bookmark</a> &emsp;<a href="https://github.com/FleyX/bookmark/issues">反馈/建议</a></div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: "Bottom" name: "Bottom",
}; };
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "../../global"; @import "../../global";
.main { .main {
background-color: gray; background-color: rgb(207, 198, 198);
height: @bottomHeight; height: @bottomHeight;
display: flex; display: flex;
justify-content: center; justify-content: center;

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="main"> <div class="main">
<img class="ico" src="/static/img/bookmarkLogo.png" /> <a class="ico" href="/"><img src="/static/img/bookmarkLogo.png" /></a>
<a-dropdown> <a-dropdown>
<div class="user"> <div class="user">
<img :src="userInfo.icon" class="userIcon" /> <img :src="userInfo.icon" class="userIcon" />
@ -52,6 +52,7 @@ export default {
background-color: rgba(197, 190, 198, 0.4); background-color: rgba(197, 190, 198, 0.4);
z-index: 100; z-index: 100;
.ico { .ico {
display: flex;
height: 100%; height: 100%;
} }
.user { .user {

View File

@ -1,4 +1,5 @@
import localforage from "localforage"; import localforage from "localforage";
import HttpUtil from "../../util/HttpUtil";
/** /**
* 存储全局配置 * 存储全局配置
*/ */
@ -36,6 +37,11 @@ const actions = {
context.commit("isInit", true); context.commit("isInit", true);
context.commit("isPhone", /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)); context.commit("isPhone", /Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent));
}, },
async refreshUserInfo({ commit }) {
let userInfo = await HttpUtil.get("/user/currentUserInfo");
await localforage.setItem("userInfo", userInfo);
commit("setUserInfo", userInfo);
},
//登出清除数据 //登出清除数据
async clear(context) { async clear(context) {
await localforage.removeItem("userInfo"); await localforage.removeItem("userInfo");

View File

@ -11,11 +11,52 @@
</div> </div>
<div class="baseInfo"> <div class="baseInfo">
<div class="item"> <div class="item">
<span>昵称</span>
<span>{{userInfo.name}}</span> <a-tooltip title="点击修改" v-if="currentAction!='name'">
<span style="font-size:2em;cursor: pointer;" @click="()=>this.currentAction='name'">{{userInfo.username}}</span>
</a-tooltip>
<div class="inputGroup" v-else-if="currentAction==='name'">
<a-input type="text" v-model="name" placeholder="修改昵称" />
<div style="padding-top:0.2em">
<a-button style="margin-right:2em" type="warn" @click="()=>this.currentAction=null">取消</a-button>
<a-button type="primary" @click="submit">确定</a-button>
</div> </div>
</div> </div>
</div> </div>
<div class="item">
<span style="width:5em">密码</span>
<a-tooltip title="点击修改" v-if="currentAction!='password'">
<span style="cursor: pointer;" @click="()=>this.currentAction='password'">**********</span>
</a-tooltip>
<div class="inputGroup" v-else-if="currentAction==='password'">
<a-input type="password" v-model="oldPassword" placeholder="旧密码" />
<a-input type="password" v-model="password" placeholder="新密码" />
<a-input type="password" v-model="rePassword" placeholder="重复新密码" />
<div style="padding-top:0.2em">
<a-button style="margin-right:2em" type="warn" @click="()=>this.currentAction=null">取消</a-button>
<a-button type="primary" @click="submit">确定</a-button>
</div>
</div>
</div>
<div class="item">
<span style="width:5em">邮箱</span>
<a-tooltip title="点击修改" v-if="currentAction!='email'">
<span style="cursor: pointer;" @click="()=>this.currentAction='email'">{{userInfo.email}}</span>
</a-tooltip>
<div class="inputGroup" v-else-if="currentAction==='email'">
<a-input type="password" v-model="oldPassword" placeholder="旧密码" />
<a-input type="email" v-model="email" placeholder="email" />
<div style="padding-top:0.2em">
<a-button style="margin-right:2em" type="warn" @click="()=>this.currentAction=null">取消</a-button>
<a-button type="primary" @click="submit">确定</a-button>
</div>
</div>
</div>
</div>
</div>
</template> </template>
<script> <script>
@ -23,15 +64,24 @@ import { mapState } from "vuex";
import HttpUtil from "../../../../util/HttpUtil"; import HttpUtil from "../../../../util/HttpUtil";
export default { export default {
name: "UserInfo", name: "UserInfo",
data() {
return {
currentAction: null, //,name,password,email
name: "",
oldPassword: "",
password: "",
rePassword: "",
email: "",
};
},
computed: { computed: {
...mapState("globalConfig", ["userInfo"]), ...mapState("globalConfig", ["userInfo"]),
}, },
methods: { methods: {
async changeIcon(e) { async changeIcon(e) {
let file = e.target.files[0]; let file = e.target.files[0];
console.log(file); if (!file || file.size > 200 * 1024) {
if (!file || file.size > 500 * 1024 * 8) { message.error("文件大小请勿超过200KB");
message.error("文件大小请勿超过500KB");
return; return;
} }
let formData = new FormData(); let formData = new FormData();
@ -39,6 +89,30 @@ export default {
let res = await HttpUtil.post("/user/icon", null, formData, true); let res = await HttpUtil.post("/user/icon", null, formData, true);
this.$set(this.userInfo, "icon", res); this.$set(this.userInfo, "icon", res);
}, },
async submit() {
let url, body;
if (this.currentAction === "name") {
url = "/baseInfo/username";
body = { username: this.name };
} else if (this.currentAction === "password") {
if (!this.password === this.rePassword) {
this.$message.error("新密码两次输入不一致");
return;
}
url = "/baseInfo/password";
body = {
oldPassword: this.oldPassword,
password: this.password,
};
} else {
url = "/baseInfo/email";
body = { oldPassword: this.oldPassword, email: this.email };
}
await HttpUtil.post(url, null, body);
await this.$store.dispatch("globalConfig/refreshUserInfo");
this.$message.success("操作成功");
this.currentAction = null;
},
}, },
}; };
</script> </script>
@ -54,6 +128,7 @@ export default {
position: relative; position: relative;
border-radius: 5px; border-radius: 5px;
margin-right: 1em; margin-right: 1em;
cursor: pointer;
@media (min-width: 768px) { @media (min-width: 768px) {
width: 150px; width: 150px;
height: 150px; height: 150px;
@ -85,6 +160,18 @@ export default {
} }
} }
.item {
font-size: 1.5em;
padding-top: 1em;
padding-bottom: 1em;
border-bottom: 1px solid #ebebeb;
display: flex;
.inputGroup {
flex: 1;
}
}
.baseInfo { .baseInfo {
flex: 1; flex: 1;
} }