Files
django-vue3-admin/web/src/views/system/personal/index.vue
猿小天 0c38495515 feat(个人中心): 个人中心
个人中心完成
2023-03-12 22:39:23 +08:00

525 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="personal layout-pd">
<el-row>
<!-- 个人信息 -->
<el-col :xs="24" :sm="16">
<el-card shadow="hover" header="个人信息">
<div class="personal-user">
<div class="personal-user-left">
<el-upload class="h100 personal-user-left-upload" :action="uploadAvatar.action" :headers="uploadAvatar.headers" multiple :limit="1">
<img v-if="state.personalForm.avatar" :src="state.personalForm.avatar" />
<img v-else src="https://img2.baidu.com/it/u=1978192862,2048448374&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=500" />
</el-upload>
</div>
<div class="personal-user-right">
<el-row>
<el-col :span="24" class="personal-title mb18">{{ currentTime }}{{state.personalForm.username}}生活变的再糟糕也不妨碍我变得更好 </el-col>
<el-col :span="24">
<el-row>
<el-col :xs="24" :sm="8" class="personal-item mb6">
<div class="personal-item-label">昵称</div>
<div class="personal-item-value">{{state.personalForm.name}}</div>
</el-col>
<el-col :xs="24" :sm="16" class="personal-item mb6">
<div class="personal-item-label">部门</div>
<div class="personal-item-value">
<el-tag >{{state.personalForm.dept_info.dept_name}}</el-tag>
</div>
</el-col>
</el-row>
</el-col>
<el-col :span="24">
<el-row>
<el-col :xs="24" :sm="24" class="personal-item mb6">
<div class="personal-item-label">角色</div>
<div class="personal-item-value">
<el-tag v-for="(item,index) in state.personalForm.role_info" :key="index">{{item.name}}</el-tag>
</div>
</el-col>
</el-row>
</el-col>
</el-row>
</div>
</div>
</el-card>
</el-col>
<!-- 消息通知 -->
<el-col :xs="24" :sm="8" class="pl15 personal-info">
<el-card shadow="hover">
<template #header>
<span>消息通知</span>
<span class="personal-info-more" @click="msgMore">更多</span>
</template>
<div class="personal-info-box">
<ul class="personal-info-ul">
<li v-for="(v, k) in state.newsInfoList" :key="k" class="personal-info-li">
<div class="personal-info-li-title">
[{{v.creator_name}},{{v.create_datetime}}] {{v.title}}
</div>
</li>
</ul>
</div>
</el-card>
</el-col>
<!-- 更新信息 -->
<el-col :span="24">
<el-card shadow="hover" class="mt15 personal-edit" header="更新信息">
<div class="personal-edit-title">基本信息</div>
<el-form :model="state.personalForm" ref="userInfoFormRef" :rules="rules" size="default" label-width="50px" class="mt35 mb35">
<el-row :gutter="35">
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="昵称" prop="name">
<el-input v-model="state.personalForm.name" placeholder="请输入昵称" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="邮箱">
<el-input v-model="state.personalForm.email" placeholder="请输入邮箱" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="手机" prop="mobile">
<el-input v-model="state.personalForm.mobile" placeholder="请输入手机" clearable></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mb20">
<el-form-item label="性别">
<el-select v-model="state.personalForm.gender" placeholder="请选择性别" clearable class="w100">
<el-option label="男" :value="1"></el-option>
<el-option label="女" :value="0"></el-option>
<el-option label="保密" :value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<el-form-item>
<el-button type="primary" @click="submitForm">
<el-icon>
<ele-Position />
</el-icon>
更新个人信息
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="personal-edit-title mb15">账号安全</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">账户密码</div>
<div class="personal-edit-safe-item-left-value">当前密码强度</div>
</div>
<div class="personal-edit-safe-item-right">
<el-button text type="primary" @click="passwordFormShow=true">立即修改</el-button>
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">密保手机</div>
<div class="personal-edit-safe-item-left-value">已绑定手机{{state.personalForm.mobile}}</div>
</div>
<div class="personal-edit-safe-item-right">
<!-- <el-button text type="primary">立即修改</el-button>-->
</div>
</div>
</div>
<div class="personal-edit-safe-box">
<div class="personal-edit-safe-item">
<div class="personal-edit-safe-item-left">
<div class="personal-edit-safe-item-left-label">绑定邮箱</div>
<div class="personal-edit-safe-item-left-value">已绑定邮箱{{state.personalForm.email}}</div>
</div>
<div class="personal-edit-safe-item-right">
<!-- <el-button text type="primary">立即设置</el-button>-->
</div>
</div>
</div>
</el-card>
</el-col>
</el-row>
<!-- 密码修改-->
<el-dialog v-model="passwordFormShow" title="密码修改">
<el-form
ref="userPasswordFormRef"
:model="userPasswordInfo"
required-asterisk
label-width="100px"
label-position="left"
:rules="passwordRules"
center
>
<el-form-item label="原密码" required prop="oldPassword">
<el-input
v-model="userPasswordInfo.oldPassword"
placeholder="请输入原始密码"
clearable
></el-input>
</el-form-item>
<el-form-item required prop="newPassword" label="新密码">
<el-input
type="password"
v-model="userPasswordInfo.newPassword"
placeholder="请输入新密码"
show-password
clearable
></el-input>
</el-form-item>
<el-form-item required prop="newPassword2" label="确认密码">
<el-input
type="password"
v-model="userPasswordInfo.newPassword2"
placeholder="请再次输入新密码"
show-password
clearable
></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="settingPassword">
<i class="fa fa-check"></i>提交
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="personal">
import { reactive, computed,onMounted,ref } from 'vue';
import { formatAxis } from '/@/utils/formatTime';
import * as api from './api'
import {ElMessage } from "element-plus";
import {getBaseURL} from "/@/utils/baseUrl";
import { Session } from '/@/utils/storage';
// 当前时间提示语
const currentTime = computed(() => {
return formatAxis(new Date());
});
const userInfoFormRef = ref()
const rules = reactive({
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }]
})
// 定义变量内容
const uploadAvatar = reactive({
action:getBaseURL() + 'api/system/file/',
headers: {
Authorization: 'JWT ' + Session.get('token')
},
})
const state = reactive<PersonalState>({
newsInfoList:[],
personalForm: {
avatar:'',
username:'',
name: '',
email: '',
mobile: '',
gender:'',
dept_info:{
dept_id:0,
dept_name:''
},
role_info:[{
id:0,
name:''
}]
},
});
/**
* 跳转消息中心
*/
import {useRouter } from "vue-router";
import {Session} from "/@/utils/storage";
const route = useRouter()
const msgMore=()=>{
route.push({path:'/messageCenter'})
}
/**
* 获取用户个人信息
*/
const getUserInfo = function (){
api.GetUserInfo({}).then((res:any)=>{
const {data} = res
state.personalForm.avatar = data.avatar || '';
state.personalForm.username = data.username || '';
state.personalForm.name = data.name || '';
state.personalForm.email = data.email || '';
state.personalForm.mobile = data.mobile || '';
state.personalForm.gender = data.gender || '';
state.personalForm.dept_info.dept_name = data.dept_info.dept_name || '';
state.personalForm.role_info = data.role_info || [];
})
}
/**
* 更新用户信息
* @param formEl
*/
const submitForm = async () => {
if (!userInfoFormRef.value) return
await userInfoFormRef.value.validate((valid, fields) => {
if (valid) {
api.updateUserInfo(state.personalForm).then((res:any)=>{
ElMessage.success('更新成功')
getUserInfo()
})
} else {
ElMessage.error('表单验证失败,请检查~')
}
})
}
/**
* 获取消息通知
*/
const getMsg = () => {
api.GetSelfReceive({}).then((res:any)=>{
const {data} = res
state.newsInfoList = data || [];
})
}
onMounted(()=>{
getUserInfo();
getMsg();
})
/**************************密码修改部分************************/
const passwordFormShow = ref(false)
const userPasswordFormRef = ref()
const userPasswordInfo=reactive({
oldPassword: '',
newPassword: '',
newPassword2: ''
})
const validatePass = (rule, value, callback) => {
const pwdRegex = new RegExp('(?=.*[0-9])(?=.*[a-zA-Z]).{8,30}')
if (value === '') {
callback(new Error('请输入密码'))
} else if (value === userPasswordInfo.oldPassword) {
callback(new Error('原密码与新密码一致'))
} else if (!pwdRegex.test(value)) {
callback(new Error('您的密码复杂度太低(密码中必须包含字母、数字)'))
} else {
if (userPasswordInfo.newPassword2 !== '') {
userPasswordFormRef.value.validateField('newPassword2')
}
callback()
}
}
const validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== userPasswordInfo.newPassword) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
}
const passwordRules=reactive({
oldPassword: [
{
required: true,
message: '请输入原密码',
trigger: 'blur'
}
],
newPassword: [{ validator: validatePass, trigger: 'blur' }],
newPassword2: [{ validator: validatePass2, trigger: 'blur' }]
})
/**
* 重新设置密码
*/
const settingPassword= ()=>{
userPasswordFormRef.value.validate((valid) => {
if (valid) {
api.UpdatePassword(userPasswordInfo).then((res:any)=>{
ElMessage.success('密码修改成功')
})
} else {
// 校验失败
// 登录表单校验失败
ElMessage.error('表单校验失败,请检查')
}
})
}
</script>
<style scoped lang="scss">
@import '/@/theme/mixins/index.scss';
.personal {
.personal-user {
height: 130px;
display: flex;
align-items: center;
.personal-user-left {
width: 100px;
height: 130px;
border-radius: 3px;
:deep(.el-upload) {
height: 100%;
}
.personal-user-left-upload {
img {
width: 100%;
height: 100%;
border-radius: 3px;
}
&:hover {
img {
animation: logoAnimation 0.3s ease-in-out;
}
}
}
}
.personal-user-right {
flex: 1;
padding: 0 15px;
.personal-title {
font-size: 18px;
@include text-ellipsis(1);
}
.personal-item {
display: flex;
align-items: center;
font-size: 13px;
.personal-item-label {
color: var(--el-text-color-secondary);
@include text-ellipsis(1);
}
.personal-item-value {
@include text-ellipsis(1);
}
}
}
}
.personal-info {
.personal-info-more {
float: right;
color: var(--el-text-color-secondary);
font-size: 13px;
&:hover {
color: var(--el-color-primary);
cursor: pointer;
}
}
.personal-info-box {
height: 130px;
overflow: hidden;
.personal-info-ul {
list-style: none;
.personal-info-li {
font-size: 13px;
padding-bottom: 10px;
.personal-info-li-title {
display: inline-block;
@include text-ellipsis(1);
color: var(--el-text-color-secondary);
text-decoration: none;
}
& a:hover {
color: var(--el-color-primary);
cursor: pointer;
}
}
}
}
}
.personal-recommend-row {
.personal-recommend-col {
.personal-recommend {
position: relative;
height: 100px;
border-radius: 3px;
overflow: hidden;
cursor: pointer;
&:hover {
i {
right: 0px !important;
bottom: 0px !important;
transition: all ease 0.3s;
}
}
i {
position: absolute;
right: -10px;
bottom: -10px;
font-size: 70px;
transform: rotate(-30deg);
transition: all ease 0.3s;
}
.personal-recommend-auto {
padding: 15px;
position: absolute;
left: 0;
top: 5%;
color: var(--next-color-white);
.personal-recommend-msg {
font-size: 12px;
margin-top: 10px;
}
}
}
}
}
.personal-edit {
.personal-edit-title {
position: relative;
padding-left: 10px;
color: var(--el-text-color-regular);
&::after {
content: '';
width: 2px;
height: 10px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
background: var(--el-color-primary);
}
}
.personal-edit-safe-box {
border-bottom: 1px solid var(--el-border-color-light, #ebeef5);
padding: 15px 0;
.personal-edit-safe-item {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.personal-edit-safe-item-left {
flex: 1;
overflow: hidden;
.personal-edit-safe-item-left-label {
color: var(--el-text-color-regular);
margin-bottom: 5px;
}
.personal-edit-safe-item-left-value {
color: var(--el-text-color-secondary);
@include text-ellipsis(1);
margin-right: 15px;
}
}
}
&:last-of-type {
padding-bottom: 0;
border-bottom: none;
}
}
}
}
</style>