feat(个人中心): ✨ 个人中心
个人中心完成
This commit is contained in:
@@ -14,6 +14,7 @@ export default {
|
||||
limitsFrontEndBtn: 'FrontEndBtn',
|
||||
limitsBackEnd: 'BackEnd',
|
||||
limitsBackEndEndPage: 'BackEndEndPage',
|
||||
personal: 'personal',
|
||||
},
|
||||
staticRoutes: {
|
||||
signIn: 'signIn',
|
||||
|
||||
@@ -25,6 +25,7 @@ export default {
|
||||
limitsFrontEndBtn: '按钮权限',
|
||||
limitsBackEnd: '后端控制',
|
||||
limitsBackEndEndPage: '页面权限',
|
||||
personal: '个人中心',
|
||||
},
|
||||
staticRoutes: {
|
||||
signIn: '登录',
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="layout-footer pb15">
|
||||
<div class="layout-footer-warp">
|
||||
<div>vue-next-admin,Made by lyt with ❤️</div>
|
||||
<div class="mt5">深圳市 xxx 公司版权所有</div>
|
||||
<div>❤️ Powered by Django-Vue3-Admin ❤️</div>
|
||||
<div class="mt5">Copyright dvadmin团队</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<div class="layout-navbars-breadcrumb-user-icon">
|
||||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||||
<template #reference>
|
||||
<el-badge :value="messageCenter.unread">
|
||||
<el-badge :value="messageCenter.unread" :hidden="messageCenter.unread===0">
|
||||
<el-icon :title="$t('message.user.title4')">
|
||||
<ele-Bell />
|
||||
</el-icon>
|
||||
@@ -68,6 +68,7 @@
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="/personal">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
|
||||
<el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item>
|
||||
<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
|
||||
@@ -32,6 +32,20 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
path: '/personal',
|
||||
name: 'personal',
|
||||
component: () => import('/@/views/system/personal/index.vue'),
|
||||
meta: {
|
||||
title: 'message.router.personal',
|
||||
isLink: '',
|
||||
isHide: false,
|
||||
isKeepAlive: true,
|
||||
isAffix: false,
|
||||
isIframe: false,
|
||||
icon: 'iconfont icon-gerenzhongxin',
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,7 +96,7 @@ export const useThemeConfig = defineStore('themeConfig', {
|
||||
// 是否开启 TagsView 共用
|
||||
isShareTagsView: false,
|
||||
// 是否开启 Footer 底部版权信息
|
||||
isFooter: false,
|
||||
isFooter: true,
|
||||
// 是否开启灰色模式
|
||||
isGrayscale: false,
|
||||
// 是否开启色弱模式
|
||||
|
||||
15
web/src/types/views.d.ts
vendored
15
web/src/types/views.d.ts
vendored
@@ -17,12 +17,19 @@ declare type PersonalState = {
|
||||
newsInfoList: NewInfo[];
|
||||
recommendList: Recommend[];
|
||||
personalForm: {
|
||||
username: string;
|
||||
name: string;
|
||||
email: string;
|
||||
autograph: string;
|
||||
occupation: string;
|
||||
phone: string;
|
||||
sex: string;
|
||||
mobile: string;
|
||||
gender: number | string;
|
||||
dept_info: {
|
||||
dept_id: number;
|
||||
dept_name: string;
|
||||
}
|
||||
role_info: [{
|
||||
id: number;
|
||||
name: string;
|
||||
}]
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
22
web/src/views/system/personal/api.ts
Normal file
22
web/src/views/system/personal/api.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { request } from '/@/utils/service';
|
||||
import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
|
||||
export function GetUserInfo(query: PageQuery) {
|
||||
return request({
|
||||
url: '/api/system/user/user_info/',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @param data
|
||||
*/
|
||||
export function updateUserInfo(data: AddReq) {
|
||||
return request({
|
||||
url: '/api/system/user/update_user_info/',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
383
web/src/views/system/personal/index.vue
Normal file
383
web/src/views/system/personal/index.vue
Normal file
@@ -0,0 +1,383 @@
|
||||
<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="https://jsonplaceholder.typicode.com/posts/" multiple :limit="1">
|
||||
<img 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">{{state.personalForm.dept_info.dept_name}}</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">更多</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">
|
||||
<a :href="v.link" target="_block" class="personal-info-li-title">{{ v.title }}</a>
|
||||
</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="phone">
|
||||
<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">立即修改</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>
|
||||
</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";
|
||||
|
||||
const userInfoFormRef = ref()
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
|
||||
mobile: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号' }]
|
||||
})
|
||||
// 定义变量内容
|
||||
const state = reactive<PersonalState>({
|
||||
personalForm: {
|
||||
username:'',
|
||||
name: '',
|
||||
email: '',
|
||||
mobile: '',
|
||||
gender:'',
|
||||
dept_info:{
|
||||
dept_id:0,
|
||||
dept_name:''
|
||||
},
|
||||
role_info:[{
|
||||
id:0,
|
||||
name:''
|
||||
}]
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取用户个人信息
|
||||
*/
|
||||
const getUserInfo = function (){
|
||||
api.GetUserInfo({}).then((res:any)=>{
|
||||
const {data} = res
|
||||
console.log(data)
|
||||
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('表单验证失败,请检查~')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
onMounted(()=>{
|
||||
getUserInfo();
|
||||
})
|
||||
|
||||
|
||||
// 当前时间提示语
|
||||
const currentTime = computed(() => {
|
||||
return formatAxis(new Date());
|
||||
});
|
||||
</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>
|
||||
Reference in New Issue
Block a user