Files
guofu-admin/src/layout/components/header-tools.vue

361 lines
11 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="ele-admin-header-tool">
<div class="ele-admin-header-tool-item">
<a-tree-select
show-search
tree-node-filter-prop="title"
treeDefaultExpandAll
:bordered="bordered"
:tree-data="menuTree"
:placeholder="`订单管理`"
:value="parentId || undefined"
style="width: 180px"
v-if="menuTree.length"
:dropdown-style="{ maxHeight: '560px', overflow: 'auto' }"
@change="onChange"
>
<template #suffixIcon><SearchOutlined /></template>
</a-tree-select>
</div>
<!-- 商户名称 -->
<template v-if="merchants.length > 0">
<div class="ele-admin-header-tool-item">
<MerchantSelect
:merchants="merchants"
v-model:value="merchantName"
@done="onMerchant"
/>
</div>
</template>
<!-- 消息通知 -->
<div class="ele-admin-header-tool-item" @click="openUrl(`/user/notice`)">
<header-notice />
</div>
<!-- 全屏切换 -->
<div
:class="[
'ele-admin-header-tool-item',
{ 'hidden-sm-and-down': styleResponsive }
]"
@click="toggleFullscreen"
>
<fullscreen-exit-outlined v-if="fullscreen" />
<fullscreen-outlined v-else />
</div>
<!-- 语言切换 -->
<!-- <div class="ele-admin-header-tool-item">-->
<!-- <i18n-icon />-->
<!-- </div>-->
<!-- 用户信息 -->
<div class="ele-admin-header-tool-item">
<a-dropdown placement="bottom" :overlay-style="{ minWidth: '280px' }">
<div class="ele-admin-header-avatar">
<a-avatar :src="loginUser.avatar">
<template v-if="!loginUser.avatar" #icon>
<user-outlined />
</template>
</a-avatar>
<span :class="{ 'hidden-sm-and-down': styleResponsive }">
{{ loginUser.nickname }}
</span>
<down-outlined style="margin-left: 6px" />
</div>
<template #overlay>
<a-menu :selectable="false" @click="onUserDropClick">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<div class="user-profile">
<div class="user-info">
<div class="nickname">
<span class="ele-text-heading">
{{ loginUser.nickname }}
</span>
<div class="ele-text-placeholder">
用户ID<span class="ele-text-secondary">{{
loginUser.userId
}}</span>
<copy-outlined
style="margin-left: 10px"
@click="copyText(loginUser.userId)"
/>
</div>
<div class="role" style="margin-top: 10px">
<template
v-for="(item, index) in loginUser.roles"
:key="item.roleId"
>
<a-tag color="blue" v-if="index === 0">
<div class="role-name">
<span>{{ item.roleName }}</span>
<span v-if="index === 1"></span>
</div>
</a-tag>
</template>
</div>
</div>
</div>
</div>
</a-card>
<a-menu-divider />
<a-menu-item key="profile">
<div class="ele-cell">
<div class="ele-cell-content"> 个人中心 </div>
</div>
</a-menu-item>
<a-menu-divider />
<a-menu-item key="password">
<div class="ele-cell">
<div class="ele-cell-content"> 修改密码 </div>
</div>
</a-menu-item>
<template v-if="loginUser.username == 'admin'">
<a-menu-divider />
<a-menu-item key="accessKey" v-if="loginUser.username == 'admin'">
<div class="ele-cell">
<div class="ele-cell-content"> 秘钥管理 </div>
</div>
</a-menu-item>
<a-menu-divider />
<a-menu-item key="skin" v-if="loginUser.username == 'admin'">
<div class="ele-cell">
<div class="ele-cell-content"> 偏好设置 </div>
</div>
</a-menu-item>
<a-menu-divider />
<a-menu-item key="system" v-if="loginUser.username == 'admin'">
<div class="ele-cell">
<div class="ele-cell-content"> 系统设置 </div>
</div>
</a-menu-item>
</template>
<a-menu-divider />
<a-menu-item key="logout">
<div class="ele-cell" align="center">
<div class="ele-cell-content">
{{ t('layout.header.logout') }}
</div>
</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
<!-- 主题设置 -->
<!-- <div class="ele-admin-header-tool-item" @click="openSetting">-->
<!-- <more-outlined />-->
<!-- </div>-->
</div>
<!-- 修改密码弹窗 -->
<password-modal v-model:visible="passwordVisible" />
<!-- 主题设置抽屉 -->
<setting-drawer v-model:visible="settingVisible" />
</template>
<script lang="ts" setup>
import { computed, createVNode, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { Modal } from 'ant-design-vue/es';
import {
DownOutlined,
CopyOutlined,
ExclamationCircleOutlined,
FullscreenOutlined,
FullscreenExitOutlined,
SearchOutlined
} from '@ant-design/icons-vue';
import { storeToRefs } from 'pinia';
import { copyText, openNew, openUrl } from '@/utils/common';
import { useThemeStore } from '@/store/modules/theme';
import HeaderNotice from './header-notice.vue';
import PasswordModal from './password-modal.vue';
import SettingDrawer from './setting-drawer.vue';
import { useUserStore } from '@/store/modules/user';
import { logout } from '@/utils/page-tab-util';
import type { Menu } from '@/api/system/menu/model';
import { listMenus } from '@/api/system/menu';
import { isExternalLink, toTreeData } from 'ele-admin-pro';
import { getMerchantName } from '@/utils/merchant';
import { Merchant } from '@/api/shop/merchant/model';
import { listMerchant } from '@/api/shop/merchant';
import MerchantSelect from './merchant-select.vue';
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
// const TENANT_ID = localStorage.getItem('TenantId');
// const TENANT_NAME = localStorage.getItem('TenantName');
const emit = defineEmits<{
(e: 'fullscreen'): void;
}>();
defineProps<{
// 是否是全屏
fullscreen: boolean;
}>();
const { push } = useRouter();
const { t } = useI18n();
const userStore = useUserStore();
// 是否显示修改密码弹窗
const passwordVisible = ref(false);
// 是否显示主题设置抽屉
const settingVisible = ref(false);
// 当前用户信息
const loginUser = computed(() => userStore.info ?? {});
const menuList = ref<Menu[]>([]);
const menuTree = ref<Menu[]>([]);
const parentId = ref<number>();
const bordered = ref<boolean>(false);
const merchants = ref<Merchant[]>([]);
const merchantName = ref();
/* 用户信息下拉点击 */
const onUserDropClick = ({ key }) => {
if (key === 'password') {
passwordVisible.value = true;
} else if (key === 'profile') {
push('/user-center');
} else if (key === 'accessKey') {
push('/system/access-key');
} else if (key === 'taskAdd') {
push('/user/task/add');
} else if (key === 'myTask') {
push('/user/task/index');
} else if (key === 'skin') {
settingVisible.value = true;
} else if (key === 'system') {
push('/system/setting');
} else if (key === 'logout') {
// 退出登录
Modal.confirm({
title: t('layout.logout.title'),
content: t('layout.logout.message'),
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
logout();
}
});
}
};
const myOrder = () => {
push('/user/my-balance-log');
};
const onChange = (index: number) => {
const item = menuList.value.find((d) => d.menuId == index);
const isExternal = isExternalLink(item?.path);
if (isExternal) {
return openNew(`${item?.path}`);
}
if (item?.parentId == 0) {
return push(item.path);
}
if (item?.component) {
return push(item.path);
}
};
// 选择商户
const onMerchant = (id: number) => {
const item = merchants.value.find((d) => d.merchantId == id);
if (item) {
merchantName.value = item.merchantName;
localStorage.setItem('MerchantName', `${item.merchantName}`);
localStorage.setItem('MerchantId', `${item.merchantId}`);
window.location.reload();
}
};
/* 切换全屏 */
const toggleFullscreen = () => {
emit('fullscreen');
};
/* 打开主题设置抽屉 */
const openSetting = () => {
settingVisible.value = true;
};
const reload = () => {
if (loginUser.value.username == 'admin') {
// 查询菜单列表
listMenus({ menuType: 0, hide: 0 }).then((data) => {
if (data) {
menuList.value = data;
menuTree.value = toTreeData({
data: data.map((d) => {
return { ...d, key: d.menuId, value: d.menuId };
}),
idField: 'menuId',
parentIdField: 'parentId'
});
}
});
}
merchantName.value = getMerchantName();
if (loginUser.value.merchants) {
listMerchant({ merchantIds: loginUser.value.merchants }).then((res) => {
merchants.value = res.map((d) => {
d.label = d.merchantName;
d.value = d.merchantId;
return d;
});
});
}
};
reload();
</script>
<script lang="ts">
import * as icons from '@/layout/menu-icons';
export default {
components: icons,
data() {
return {
iconData: [
{
title: '已引入的图标',
icons: Object.keys(icons)
}
]
};
}
};
</script>
<style lang="less" scoped>
.ant-select {
color: #bfbfbf;
}
.user-profile {
display: flex;
.user-info {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
.nickname {
display: flex;
flex-direction: column;
}
}
}
.ele-admin-header-tool-item {
:deep(.ant-select-tree-switcher) {
background-color: #ff00fe;
}
:deep(.ant-select-tree-indent) {
display: none;
}
}
</style>