mart-admin/src/layout/navBars/topBar/user.vue
2025-01-10 10:50:02 +08:00

381 lines
12 KiB
Vue

<template>
<div class="layout-navbars-breadcrumb-user pr15" :style="{ flex: layoutUserFlexNum }">
<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onComponentSizeChange">
<div class="layout-navbars-breadcrumb-user-icon">
<i class="iconfont icon-ziti" :title="$t('message.user.title0')"></i>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="large" :disabled="state.disabledSize === 'large'">{{ $t('message.user.dropdownLarge') }}</el-dropdown-item>
<el-dropdown-item command="default" :disabled="state.disabledSize === 'default'">{{ $t('message.user.dropdownDefault') }}</el-dropdown-item>
<el-dropdown-item command="small" :disabled="state.disabledSize === 'small'">{{ $t('message.user.dropdownSmall') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- <el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
<div class="layout-navbars-breadcrumb-user-icon">
<i
class="iconfont"
:class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'"
:title="$t('message.user.title1')"
></i>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="zh-cn" :disabled="state.disabledI18n === 'zh-cn'">简体中文</el-dropdown-item>
<el-dropdown-item command="en" :disabled="state.disabledI18n === 'en'">English</el-dropdown-item>
<el-dropdown-item command="zh-tw" :disabled="state.disabledI18n === 'zh-tw'">繁體中文</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown> -->
<!-- <div class="layout-navbars-breadcrumb-user-icon" @click="onSearchClick">
<el-icon :title="$t('message.user.title2')">
<ele-Search />
</el-icon>
</div> -->
<!-- <div class="layout-navbars-breadcrumb-user-icon" @click="onLayoutSetingClick">
<i class="icon-skin iconfont" :title="$t('message.user.title3')"></i>
</div> -->
<!-- <div class="layout-navbars-breadcrumb-user-icon" ref="userNewsBadgeRef" v-click-outside="onUserNewsClick">
<el-badge :is-dot="true">
<el-icon :title="$t('message.user.title4')">
<ele-Bell />
</el-icon>
</el-badge>
</div> -->
<el-popover
ref="userNewsRef"
:virtual-ref="userNewsBadgeRef"
placement="bottom"
trigger="click"
transition="el-zoom-in-top"
virtual-triggering
:width="300"
:persistent="false"
>
<UserNews />
</el-popover>
<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onScreenfullClick">
<i
class="iconfont"
:title="state.isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
:class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"
></i>
</div>
<el-dropdown :show-timeout="70" :hide-timeout="50" @command="onHandleCommandClick">
<span class="layout-navbars-breadcrumb-user-link">
<img :src="userInfos.photo" class="layout-navbars-breadcrumb-user-link-photo mr5" />
{{ userInfos.userName === '' ? 'common' : userInfos.userName }}
<el-icon class="el-icon--right">
<ele-ArrowDown />
</el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item>
<!-- <el-dropdown-item command="wareHouse">{{ $t('message.user.dropdown6') }}</el-dropdown-item> -->
<!-- <el-dropdown-item>
<el-button text style="height: 20px; ">
修改密码
</el-button>
</el-dropdown-item> -->
<el-dropdown-item command="updatepwd">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
<!-- <el-dropdown-item command="/404">{{ $t('message.user.dropdown3') }}</el-dropdown-item>
<el-dropdown-item command="/401">{{ $t('message.user.dropdown4') }}</el-dropdown-item> -->
<el-dropdown-item divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<Search ref="searchRef" />
<div class="system-menu-dialog-container">
<el-dialog :title="state.dialog.title" v-model="state.dialog.isShowDialog" width="400px">
<el-form ref="userDialogFormRef" :rules="state.rules" :model="state.userDetailList" size="default" label-width="120px" v-loading="state.dialog.loading">
<el-form-item label="旧密码:" prop="old">
<el-input v-model="state.userDetailList.old"></el-input>
</el-form-item>
<el-form-item label="新密码:" prop="pwd">
<el-input v-model="state.userDetailList.pwd" placeholder="请输入新密码" clearable />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button plain @click="handleSure" type="primary" size="default">确 定</el-button>
<el-button plain @click="onCancel" size="default">关 闭</el-button>
</span>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="ts" name="layoutBreadcrumbUser">
import { defineAsyncComponent, ref, unref, computed, reactive, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessageBox, ElMessage, ClickOutside as vClickOutside } from 'element-plus';
import screenfull from 'screenfull';
import { useI18n } from 'vue-i18n';
import { storeToRefs } from 'pinia';
import { useUserInfo } from '/@/stores/userInfo';
import { useThemeConfig } from '/@/stores/themeConfig';
import other from '/@/utils/other';
import mittBus from '/@/utils/mitt';
import { Session, Local } from '/@/utils/storage';
import { useLoginApi } from '/@/api/login';
import { userApi } from '/@/api/user'
// 引入组件
const UserNews = defineAsyncComponent(() => import('/@/layout/navBars/topBar/userNews.vue'));
const Search = defineAsyncComponent(() => import('/@/layout/navBars/topBar/search.vue'));
// 引入 api 请求接口
const loginApi = useLoginApi();
const userapi = userApi();
// 定义变量内容
const userNewsRef = ref();
const userNewsBadgeRef = ref();
const { locale, t } = useI18n();
const router = useRouter();
const stores = useUserInfo();
const storesThemeConfig = useThemeConfig();
const { userInfos } = storeToRefs(stores);
const { themeConfig } = storeToRefs(storesThemeConfig);
const searchRef = ref();
const state = reactive({
isScreenfull: false,
disabledI18n: 'zh-cn',
disabledSize: 'large',
userDetailList:{
old:'',
pwd:'',
},
dialog:{
isShowDialog: false,
title: '修改密码',
loading: false,
},
rules:{
old:{ required: true, message: '旧密码不能为空', trigger: 'blur' },
pwd:{ required: true, message: '新密码不能为空', trigger: 'blur' }
}
});
const userDialogFormRef = ref();
// 设置分割样式
const layoutUserFlexNum = computed(() => {
let num: string | number = '';
const { layout, isClassicSplitMenu } = themeConfig.value;
const layoutArr: string[] = ['defaults', 'columns'];
if (layoutArr.includes(layout) || (layout === 'classic' && !isClassicSplitMenu)) num = '1';
else num = '';
return num;
});
// 全屏点击时
const onScreenfullClick = () => {
if (!screenfull.isEnabled) {
ElMessage.warning('暂不不支持全屏');
return false;
}
screenfull.toggle();
screenfull.on('change', () => {
if (screenfull.isFullscreen) state.isScreenfull = true;
else state.isScreenfull = false;
});
};
// 消息通知点击时
const onUserNewsClick = () => {
unref(userNewsRef).popperRef?.delayHide?.();
};
// 布局配置 icon 点击时
const onLayoutSetingClick = () => {
mittBus.emit('openSetingsDrawer');
};
// 下拉菜单点击时
const onHandleCommandClick = async(path: string) => {
if (path === 'logOut') {
ElMessageBox({
closeOnClickModal: false,
closeOnPressEscape: false,
title: t('message.user.logOutTitle'),
message: t('message.user.logOutMessage'),
showCancelButton: true,
confirmButtonText: t('message.user.logOutConfirm'),
cancelButtonText: t('message.user.logOutCancel'),
buttonSize: 'default',
beforeClose: async (action, instance, done) => {
if (action === 'confirm') {
try {
instance.confirmButtonLoading = true;
instance.confirmButtonText = t('message.user.logOutExit');
await loginApi.loginOut();
} catch (error) {
} finally {
done();
instance.confirmButtonLoading = false;
}
} else {
done();
}
},
})
.then(async () => {
// 清除缓存/token等
console.log('清除缓存/token等');
Session.clear();
// 使用 reload 时,不需要调用 resetRoute() 重置路由
window.location.reload();
})
.catch(() => {});
} else if (path === 'wareHouse') {
window.open('https://gitee.com/lyt-top/vue-next-admin');
} else if(path === 'updatepwd'){
state.dialog.isShowDialog = true;
state.userDetailList.pwd ='';
try{
const res = await userapi.getUserDetail(localStorage.getItem('userid'));
if(res?.success){
state.userDetailList.old = res.data.password;
// console.log(111111111,state.userDetailList.oldpwd)
}
}catch(error){
console.error(error);
}
}
else {
router.push(path);
}
};
// 关闭弹窗
const closeDialog = () => {
state.dialog.isShowDialog = false;
};
//确定
const handleSure = () =>{
userDialogFormRef.value?.validate(async(valid:boolean) =>{
if(valid){
// console.log(111111111)
try{
const res = await userapi.updatepwd(localStorage.getItem('userid'),state.userDetailList);
if(res?.success){
ElMessage.success('修改成功!');
reset();
closeDialog();
ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
.then(async () => {
// 清除缓存/token等
console.log('清除缓存/token等');
Session.clear();
// 使用 reload 时,不需要调用 resetRoute() 重置路由
window.location.reload();
window.location.href = import.meta.env.MODE === "development" ? '/' : '/pixelAdmin/'; // 去登录页
})
.catch(() => {});
}
}catch(error){
console.error(error);
ElMessage.error('修改失败!');
}
}
})
};
// 取消
const onCancel = () => {
closeDialog();
};
const reset = () =>{
state.userDetailList = {
old:'',
pwd:''
}
};
// 菜单搜索点击
const onSearchClick = () => {
searchRef.value.openSearch();
};
// 组件大小改变
const onComponentSizeChange = (size: string) => {
Local.remove('themeConfig');
themeConfig.value.globalComponentSize = size;
Local.set('themeConfig', themeConfig.value);
initI18nOrSize('globalComponentSize', 'disabledSize');
window.location.reload();
};
// 语言切换
const onLanguageChange = (lang: string) => {
Local.remove('themeConfig');
themeConfig.value.globalI18n = lang;
Local.set('themeConfig', themeConfig.value);
locale.value = lang;
other.useTitle();
initI18nOrSize('globalI18n', 'disabledI18n');
};
// 初始化组件大小/i18n
const initI18nOrSize = (value: string, attr: string) => {
(<any>state)[attr] = Local.get('themeConfig')[value];
};
// 页面加载时
onMounted(() => {
if (Local.get('themeConfig')) {
initI18nOrSize('globalComponentSize', 'disabledSize');
initI18nOrSize('globalI18n', 'disabledI18n');
}
});
</script>
<style scoped lang="scss">
.layout-navbars-breadcrumb-user {
display: flex;
align-items: center;
justify-content: flex-end;
&-link {
height: 100%;
display: flex;
align-items: center;
white-space: nowrap;
&-photo {
width: 25px;
height: 25px;
border-radius: 100%;
}
}
&-icon {
padding: 0 10px;
cursor: pointer;
color: var(--next-bg-topBarColor);
height: 50px;
line-height: 50px;
display: flex;
align-items: center;
&:hover {
background: var(--next-color-user-hover);
i {
display: inline-block;
animation: logoAnimation 0.3s ease-in-out;
}
}
}
:deep(.el-dropdown) {
color: var(--next-bg-topBarColor);
}
:deep(.el-badge) {
height: 40px;
line-height: 40px;
display: flex;
align-items: center;
}
:deep(.el-badge__content.is-fixed) {
top: 12px;
}
}
</style>