### commit message
1. 新增安全设置页面,支持修改密码功能 在管理界面新增安全设置视图,允许用户更新登录密码。实现包括表单验证、验证码发送与验证、旧密码检查及新密码设置的密码修改流程。 2. 实现用户信息展示及编辑功能 新增用户信息管理页面,展示用户的详细信息包括用户名、手机号、邮箱、所属部门、职位及创建日期。支持个人信息的查看及编辑功能,增强用户管理的便捷性。master
parent
4352df5f1e
commit
3079fc161e
|
@ -0,0 +1,211 @@
|
|||
<template>
|
||||
<div>
|
||||
<h1 style="text-align: center; margin-bottom: 30px;">安全设置</h1>
|
||||
<el-divider></el-divider>
|
||||
<label>登录密码</label>
|
||||
<label>安全性高的密码可以使帐号更安全</label>
|
||||
<button @click="openModal">修改密码</button>
|
||||
|
||||
<!-- 弹出框 -->
|
||||
<div v-if="showModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2>身份验证</h2>
|
||||
<el-divider></el-divider>
|
||||
|
||||
<!-- 手机号和验证码 -->
|
||||
<div v-if="!verificationSent">
|
||||
<label for="phonenumber">身份验证方式:</label>
|
||||
<div><h3>通过手机({{ user.phonenumber }})获取验证</h3></div>
|
||||
<button @click="sendCode">发送验证码</button>
|
||||
</div>
|
||||
|
||||
<div v-if="verificationSent && !codeVerified">
|
||||
<label for="code">验证码:</label>
|
||||
<input v-model="code" id="code" type="text" placeholder="请输入验证码" />
|
||||
<button @click="verifyCode">验证验证码</button>
|
||||
</div>
|
||||
|
||||
<div v-if="codeVerified">
|
||||
<el-form ref="form" :model="user" :rules="rules" label-width="80px">
|
||||
<el-form-item label="旧密码" prop="oldPassword">
|
||||
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" show-password type="password"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<el-input v-model="user.newPassword" placeholder="请输入新密码" show-password type="password"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" show-password type="password"/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<button @click="submit" :disabled="!user.newPassword">提交修改</button>
|
||||
</div>
|
||||
<button @click="closeModal" class="close-button">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import {getUserProfile,sendCode,checkCode} from "@/api/system/user";
|
||||
import {updateUserPwd} from "@/api/system/user";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
const equalToPassword = (rule, value, callback) => {
|
||||
if (this.user.newPassword !== value) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
// 表单校验
|
||||
rules: {
|
||||
oldPassword: [
|
||||
{required: true, message: "旧密码不能为空", trigger: "blur"}
|
||||
],
|
||||
newPassword: [
|
||||
{required: true, message: "新密码不能为空", trigger: "blur"},
|
||||
{min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur"}
|
||||
],
|
||||
confirmPassword: [
|
||||
{required: true, message: "确认密码不能为空", trigger: "blur"},
|
||||
{required: true, validator: equalToPassword, trigger: "blur"}
|
||||
]
|
||||
},
|
||||
user: {
|
||||
oldPassword: undefined,
|
||||
newPassword: undefined,
|
||||
confirmPassword: undefined
|
||||
},
|
||||
showModal: false,
|
||||
phonenumber: '',
|
||||
code: '',
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
verificationSent: false,
|
||||
codeVerified: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getUser();
|
||||
},
|
||||
methods: {
|
||||
getUser() {
|
||||
getUserProfile().then(response => {
|
||||
this.user = response.data.sysUser;
|
||||
});
|
||||
},
|
||||
openModal() {
|
||||
this.showModal = true;
|
||||
},
|
||||
closeModal() {
|
||||
this.showModal = false;
|
||||
this.resetForm();
|
||||
},
|
||||
async sendCode() {
|
||||
try {
|
||||
sendCode(this.user.phonenumber)
|
||||
this.verificationSent = true;
|
||||
alert('验证码已发送');
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败', error);
|
||||
alert('发送验证码失败');
|
||||
}
|
||||
},
|
||||
submit() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
async verifyCode() {
|
||||
checkCode(this.user.phonenumber, this.code).then(response => {
|
||||
if (response.code === 200) {
|
||||
this.codeVerified = true;
|
||||
alert('验证码验证成功');
|
||||
} else {
|
||||
alert('验证码验证失败');
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
resetForm() {
|
||||
this.phonenumber = '';
|
||||
this.code = '';
|
||||
this.oldPassword = '';
|
||||
this.newPassword = '';
|
||||
this.verificationSent = false;
|
||||
this.codeVerified = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 简单样式,仅供参考 */
|
||||
.modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
width: 400px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin-top: 5px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 20px;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
background-color: #6c757d;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
.close-button:hover {
|
||||
background-color: #c82333;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<div class="app-container">
|
||||
<el-row class="center-row" :gutter="20">
|
||||
<el-col :span="12" :xs="24">
|
||||
<el-card style="margin-top: 50px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>个人信息</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-center">
|
||||
<userAvatar/>
|
||||
</div>
|
||||
<ul class="list-group list-group-striped">
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="user"/>
|
||||
用户名称
|
||||
<div class="pull-right">{{ user.userName }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="phone"/>
|
||||
手机号码
|
||||
<div class="pull-right">{{ user.phonenumber }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="email"/>
|
||||
用户邮箱
|
||||
<div class="pull-right">{{ user.email }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="tree"/>
|
||||
所属部门
|
||||
<div v-if="user.dept" class="pull-right">{{ user.dept.deptName }} / {{ postGroup }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="peoples"/>
|
||||
职位
|
||||
<div class="pull-right">{{ roleGroup }}</div>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<svg-icon icon-class="date"/>
|
||||
创建日期
|
||||
<div class="pull-right">{{ user.createTime }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {getUserProfile} from "@/api/system/user";
|
||||
import userAvatar from "/src/views/system/user/profile/userAvatar";
|
||||
import userInfo from "/src/views/system/user/profile/userInfo";
|
||||
import resetPwd from "/src/views/system/user/profile/resetPwd";
|
||||
|
||||
export default {
|
||||
name: "Profile",
|
||||
components: {userAvatar, userInfo, resetPwd},
|
||||
data() {
|
||||
return {
|
||||
user: {},
|
||||
roleGroup: {},
|
||||
postGroup: {},
|
||||
activeTab: "userinfo"
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getUser();
|
||||
},
|
||||
methods: {
|
||||
getUser() {
|
||||
getUserProfile().then(response => {
|
||||
this.user = response.data.sysUser;
|
||||
this.roleGroup = response.data.roleGroup;
|
||||
this.postGroup = response.data.postGroup;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.app-container {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.center-row {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.box-card {
|
||||
border: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue