用户信息修改

This commit is contained in:
仲么了
2024-01-26 16:15:40 +08:00
parent 04665478fc
commit 5267ae1903
13 changed files with 457 additions and 173 deletions

View File

@@ -24,40 +24,21 @@
size="18"
/>
</div>
<el-popover
@show="onCurrentNavMenu(true, 'adminInfo')"
@hide="onCurrentNavMenu(false, 'adminInfo')"
placement="bottom-end"
:hide-after="0"
:width="260"
trigger="click"
popper-class="admin-info-box"
v-model:visible="state.showAdminInfoPopover"
>
<template #reference>
<div class="admin-info" :class="state.currentNavMenu == 'adminInfo' ? 'hover' : ''">
<el-avatar :size="25" fit="fill">
<img src="@/assets/avatar.png" alt="" />
</el-avatar>
<div class="admin-name">{{ adminInfo.nickname }}</div>
</div>
</template>
<div>
<div class="admin-info-base">
<el-avatar :size="70" fit="fill">
<img src="@/assets/avatar.png" alt="" />
</el-avatar>
<div class="admin-info-other">
<div class="admin-info-name">{{ adminInfo.nickname }}</div>
<div class="admin-info-lasttime">{{ adminInfo.last_login_time }}</div>
</div>
</div>
<div class="admin-info-footer">
<el-button @click="onAdminInfo" type="primary" plain>个人资料</el-button>
<el-button @click="onLogout" type="danger" plain>退出登录</el-button>
</div>
<el-dropdown style='height: 100%;' @command='handleCommand'>
<div class="admin-info" :class="state.currentNavMenu == 'adminInfo' ? 'hover' : ''">
<el-avatar :size="25" fit="fill">
<img src="@/assets/avatar.png" alt="" />
</el-avatar>
<div class="admin-name">{{ adminInfo.nickname }}</div>
</div>
</el-popover>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="adminInfo">个人资料</el-dropdown-item>
<el-dropdown-item command="changePwd">修改密码</el-dropdown-item>
<el-dropdown-item command="layout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div @click="configStore.setLayout('showDrawer', true)" class="nav-menu-item">
<Icon
:color="configStore.getColorVal('headerBarTabColor')"
@@ -67,27 +48,30 @@
/>
</div>
<Config />
<PopupPwd ref='popupPwd' />
<AdminInfo ref='popupAdminInfo' />
<!-- <TerminalVue /> -->
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { reactive, ref } from 'vue'
import screenfull from 'screenfull'
import { useConfig } from '@/stores/config'
import { ElMessage } from 'element-plus'
import Config from './config.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { Local, Session } from '@/utils/storage'
import { ADMIN_INFO } from '@/stores/constant/cacheKey'
import router from '@/router'
import { routePush } from '@/utils/router'
import { fullUrl } from '@/utils/common'
import html2canvas from 'html2canvas'
import PopupPwd from './popup/password.vue'
import AdminInfo from './popup/adminInfo.vue'
const adminInfo = useAdminInfo()
const configStore = useConfig()
const popupPwd = ref()
const popupAdminInfo = ref()
const state = reactive({
isFullScreen: false,
currentNavMenu: '',
@@ -99,10 +83,9 @@ const onCurrentNavMenu = (status: boolean, name: string) => {
state.currentNavMenu = status ? name : ''
}
const savePng = () => {
html2canvas(document.body,{
html2canvas(document.body, {
scale: 1,
useCORS: true
}).then(function (canvas) {
var link = document.createElement('a')
link.href = canvas.toDataURL('image/png')
@@ -126,19 +109,23 @@ const onAdminInfo = () => {
routePush({ name: 'routine/adminInfo' })
}
const onLogout = () => {
router.push({ name: 'login' })
const handleCommand = (key: string) => {
console.log(key)
switch (key) {
case 'adminInfo':
popupAdminInfo.value.open()
break
case 'changePwd':
popupPwd.value.open()
break
case 'layout':
router.push({ name: 'login' })
break
default:
break
}
}
// const onClearCache = (type: string) => {
// if (type == 'storage' || type == 'all') {
// const adminInfo = Local.get(ADMIN_INFO)
// Session.clear()
// Local.clear()
// Local.set(ADMIN_INFO, adminInfo)
// if (type == 'storage') return
// }
// }
</script>
<style scoped lang="scss">
@@ -146,12 +133,14 @@ const onLogout = () => {
border-radius: var(--el-border-radius-base);
box-shadow: var(--el-box-shadow-light);
}
.nav-menus {
display: flex;
align-items: center;
height: 100%;
margin-left: auto;
background-color: v-bind('configStore.getColorVal("headerBarBackground")');
.nav-menu-item {
height: 100%;
width: 40px;
@@ -159,16 +148,19 @@ const onLogout = () => {
align-items: center;
justify-content: center;
cursor: pointer;
.nav-menu-icon {
box-sizing: content-box;
color: v-bind('configStore.getColorVal("headerBarTabColor")');
}
&:hover {
.icon {
animation: twinkle 0.3s ease-in-out;
}
}
}
.admin-info {
display: flex;
height: 100%;
@@ -177,48 +169,58 @@ const onLogout = () => {
cursor: pointer;
user-select: none;
color: v-bind('configStore.getColorVal("headerBarTabColor")');
&:hover {
color: v-bind('configStore.getColorVal("headerBarTabActiveColor")');
}
}
.admin-name {
padding-left: 6px;
white-space: nowrap;
}
.nav-menu-item:hover,
.admin-info:hover,
.nav-menu-item.hover,
.admin-info.hover {
background: v-bind('configStore.getColorVal("headerBarHoverBackground")');
.nav-menu-icon {
color: v-bind('configStore.getColorVal("headerBarTabActiveColor")') !important;
}
}
}
.dropdown-menu-box :deep(.el-dropdown-menu__item) {
justify-content: center;
}
.admin-info-base {
display: flex;
justify-content: center;
flex-wrap: wrap;
padding-top: 10px;
.admin-info-other {
display: block;
width: 100%;
text-align: center;
padding: 10px 0;
.admin-info-name {
font-size: var(--el-font-size-large);
}
}
}
.admin-info-footer {
padding: 10px 0;
margin: 0 -12px -12px -12px;
display: flex;
justify-content: space-around;
}
.pt2 {
padding-top: 2px;
}

View File

@@ -0,0 +1,54 @@
<template>
<el-dialog class='cn-operate-dialog' v-model='dialogVisible' :title='title'>
<el-scrollbar>
<el-form :inline='false' :model='form' label-width='120px'>
<el-form-item label='用户名称:'>
<el-input v-model='form.name' :disabled='true'></el-input>
</el-form-item>
<el-form-item label='登录名称:' class='top'>
<el-input v-model='form.loginName' :disabled='true'></el-input>
</el-form-item>
<el-form-item label='归属部门名称:' class='top'>
<el-input v-model='form.deptName' :disabled='true'></el-input>
</el-form-item>
<el-form-item label='拥有的角色:' class='top'>
<el-input v-model='form.role' :disabled='true'></el-input>
</el-form-item>
<el-form-item label='电话号码:' class='top'>
<el-input v-model='form.phone' :disabled='true'></el-input>
</el-form-item>
<el-form-item label='电子邮箱:' class='top'>
<el-input v-model='form.email' :disabled='true'></el-input>
</el-form-item>
</el-form>
</el-scrollbar>
</el-dialog>
</template>
<script lang='ts' setup>
import { ref, inject } from 'vue'
import { reactive } from 'vue'
import { useAdminInfo } from '@/stores/adminInfo'
const dialogVisible = ref(false)
const title = ref('用户信息')
const adminInfo = useAdminInfo()
const formRef = ref()
const form = reactive({
name: '',
deptName: '',
phone: '',
email: '',
role: '',
loginName: ''
})
const open = () => {
dialogVisible.value = true
for (const key in form) {
form[key] = Array.isArray(adminInfo.$state[key]) ? adminInfo.$state[key].join(',') : adminInfo.$state[key]
}
}
defineExpose({ open })
</script>

View File

@@ -0,0 +1,107 @@
<template>
<el-dialog class='cn-operate-dialog' v-model='dialogVisible' :title='title'>
<el-scrollbar>
<el-form :inline='false' :model='form' label-width='120px' :rules='rules' ref='formRef'>
<el-form-item label='校验密码:' prop='password'>
<el-input v-model='form.password' type='password' placeholder='请输入校验密码' show-password />
</el-form-item>
<el-form-item label='新密码:' prop='newPwd' style='margin-top: 20px'>
<el-input v-model='form.newPwd' type='password' placeholder='请输入新密码' show-password />
</el-form-item>
<el-form-item label='确认密码:' prop='confirmPwd' style='margin-top: 20px'>
<el-input v-model='form.confirmPwd' type='password' placeholder='请输入确认密码' show-password />
</el-form-item>
</el-form>
</el-scrollbar>
<template #footer>
<span class='dialog-footer'>
<el-button @click='dialogVisible = false'>取消</el-button>
<el-button type='primary' @click='submit'>确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang='ts' setup>
import { ref, inject } from 'vue'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { passwordConfirm, updatePassword } from '@/api/user-boot/user'
import { validatePwd } from '@/utils/common'
import { useAdminInfo } from '@/stores/adminInfo'
const adminInfo = useAdminInfo()
const dialogVisible = ref(false)
const title = ref('修改密码')
const formRef = ref()
// 注意不要和表单ref的命名冲突
const form = reactive({
password: '',
newPwd: '',
confirmPwd: ''
})
const rules = {
password: [
{ required: true, message: '请输入校验密码', trigger: 'blur' },
{
min: 6,
max: 16,
message: '长度在 6 到 16 个字符',
trigger: 'blur'
}
],
newPwd: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 16,
message: '长度在 6 到 16 个字符',
trigger: 'blur'
},
{ validator: validatePwd, trigger: 'blur' }
],
confirmPwd: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{
min: 6,
max: 16,
message: '长度在 6 到 16 个字符',
trigger: 'blur'
},
{
validator: (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== form.newPwd) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
},
trigger: 'blur',
required: true
}
]
}
const open = () => {
dialogVisible.value = true
}
const submit = () => {
formRef.value.validate(async valid => {
if (valid) {
passwordConfirm(form.password)
.then(res => {
updatePassword({
id: adminInfo.$state.userIndex,
newPassword: form.newPwd
}).then((res: any) => {
ElMessage.success('密码修改成功')
dialogVisible.value = false
})
})
}
})
}
defineExpose({ open })
</script>

View File

@@ -23,6 +23,7 @@ import { adminBaseRoutePath } from '@/router/static'
import { getRouteMenu, dictDataCache } from '@/api/auth'
import { getAreaList } from '@/api/common'
import { BasicDictData } from '@/stores/interface'
import { getUserById } from '@/api/user-boot/user'
defineOptions({
components: { Default, Classic, Streamline, Double }
@@ -50,9 +51,10 @@ onBeforeMount(() => {
})
const init = async () => {
await Promise.all([getAreaList(), dictDataCache()]).then(res => {
await Promise.all([getAreaList(), dictDataCache(),getUserById()]).then(res => {
dictData.state.area = res[0].data
dictData.state.basic = res[1].data
adminInfo.dataFill(res[2].data)
})
/**
* 后台初始化请求,获取站点配置,动态路由等信息