You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
580 lines
17 KiB
580 lines
17 KiB
6 months ago
|
<!-- @format -->
|
||
|
|
||
|
<template>
|
||
|
<a-layout-header class="header">
|
||
|
<div class="logo">
|
||
|
<img
|
||
|
v-if="themeConfig.logoLessUrl"
|
||
|
:src="themeConfig.logoLessUrl"
|
||
|
style="width: 192px; height: 48px; object-fit: contain" />
|
||
|
<ns-icon v-else name="headerLogin" class="headerLogin" style="width: auto; height: 48px" />
|
||
|
</div>
|
||
|
<div class="header-menu">
|
||
|
<a-menu style="width: 100%" mode="horizontal" :selectedKeys="initHeaderKey">
|
||
|
<a-menu-item v-for="item in menuList" :key="item.name">
|
||
|
<div @click="tochildren(item)">
|
||
|
<ns-icon :name="item.meta.icon" size="16" /><span>{{ item.meta.title }}</span>
|
||
|
</div>
|
||
|
</a-menu-item>
|
||
|
<template v-for="item in subMenuList" :key="item.name">
|
||
|
<a-sub-menu v-if="getOPMenu(item.meta?.itemList)?.length > 1">
|
||
|
<template #title>
|
||
|
<ns-icon :name="item.meta.icon" size="16" /><span
|
||
|
>{{ item.meta.title }}
|
||
|
</span></template
|
||
|
>
|
||
|
<a-menu-item
|
||
|
:key="menuItem.name"
|
||
|
v-for="menuItem in item.meta?.itemList ? getOPMenu(item.meta?.itemList) : []">
|
||
|
<a
|
||
|
style="color: inherit !important"
|
||
|
:href="menuItem.url ? menuItem.url : menuItem.getUrl ? menuItem.getUrl() : ''"
|
||
|
target="_blank"
|
||
|
rel="noopener noreferrer">
|
||
|
{{ menuItem.name }}
|
||
|
</a></a-menu-item
|
||
|
>
|
||
|
</a-sub-menu>
|
||
|
|
||
|
<template v-if="checkMenus(item.meta?.itemList)?.length == 1">
|
||
|
<a-menu-item
|
||
|
:key="menuItem.name"
|
||
|
v-for="menuItem in checkMenus(item.meta?.itemList)
|
||
|
? checkMenus(item.meta?.itemList)
|
||
|
: []">
|
||
|
<div v-if="!item.meta.isNewOpen">
|
||
|
<ns-icon :name="item.meta.icon" size="16" />{{ item.meta.title }}
|
||
|
<a
|
||
|
:href="menuItem.url ? menuItem.url : menuItem.getUrl ? menuItem.getUrl() : ''"
|
||
|
target="_blank"
|
||
|
rel="noopener noreferrer">
|
||
|
</a>
|
||
|
</div>
|
||
|
<div v-else @click="toCustomUrl(menuItem.url)">
|
||
|
<ns-icon :name="item.meta.icon" size="16" />{{ item.meta.title }}
|
||
|
<a target="_blank" rel="noopener noreferrer"> </a>
|
||
|
</div>
|
||
|
</a-menu-item>
|
||
|
</template>
|
||
|
</template>
|
||
|
</a-menu>
|
||
|
</div>
|
||
|
<div class="nsHeader_action">
|
||
|
<div class="projectName action" v-if="showProject">
|
||
|
{{ projectName ? projectName : enterpriseName }}
|
||
|
</div>
|
||
|
<div
|
||
|
class="projectName action"
|
||
|
v-if="['服务管理平台', '报表中心'].includes(configStore.resourceInfo?.application?.label)"
|
||
|
@click="backDoor"
|
||
|
>{{ '返回门户' }}</div
|
||
|
>
|
||
|
<div v-if="bellInfo.isShow" class="bells action" @click="backMessage">
|
||
|
<a-badge :count="messageCount > 99 ? 99 : messageCount">
|
||
|
<ns-icon name="bells" size="32" />
|
||
|
</a-badge>
|
||
|
</div>
|
||
|
<a-dropdown :trigger="['hover']">
|
||
|
<div class="userName action">
|
||
|
<!-- <img src="/asset/image/login/adminIcon.png" /> -->
|
||
|
<ns-icon class="headerAdminIcon" name="headerAdminIcon" size="20" />
|
||
|
<span
|
||
|
style="
|
||
|
display: block;
|
||
|
max-width: 100px;
|
||
|
overflow: hidden;
|
||
|
white-space: nowrap;
|
||
|
text-overflow: ellipsis;
|
||
|
"
|
||
|
>{{ userName }}</span
|
||
|
>
|
||
|
<ns-icon class="downArrow" name="downArrow" size="20" />
|
||
|
</div>
|
||
|
|
||
|
<template #overlay>
|
||
|
<a-menu>
|
||
|
<a-menu-item
|
||
|
class="menuItem"
|
||
|
style="
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
height: 52px;
|
||
|
font-size: 14px;
|
||
|
justify-content: center;
|
||
|
color: rgba(0, 0, 0, 0.65);
|
||
|
">
|
||
|
<ns-icon name="updatePassword" size="18" style="position: relative; top: 2px" />
|
||
|
<a href="javascript:;" @click="toUpdate" style="margin-left: 10px">修改密码</a>
|
||
|
</a-menu-item>
|
||
|
<a-menu-item
|
||
|
class="menuItem"
|
||
|
style="
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
height: 52px;
|
||
|
font-size: 14px;
|
||
|
justify-content: center;
|
||
|
color: rgba(0, 0, 0, 0.65);
|
||
|
">
|
||
|
<ns-icon name="leaveout" size="14" style="position: relative; top: 2px; left: 2px" />
|
||
|
<a href="javascript:;" @click="dropOut" style="margin-left: 12px">退出登录</a>
|
||
|
</a-menu-item>
|
||
|
</a-menu>
|
||
|
</template>
|
||
|
</a-dropdown>
|
||
|
|
||
|
<!-- <div class="setting action" v-if="currentThemeColor" @click="changeSettingVisible(true)">
|
||
|
<setting-outlined />
|
||
|
</div> -->
|
||
|
</div>
|
||
|
<!-- <a-drawer v-model:visible="settingVisible" title="外观管理" placement="right">
|
||
|
<a-divider>主题</a-divider>
|
||
|
<div class="theme-picker">
|
||
|
<template v-for="color in themeColorList" :key="color">
|
||
|
<span
|
||
|
class="theme-picker_item"
|
||
|
@click="changeTheme(color)"
|
||
|
:class="{ current: currentThemeColor === color }"
|
||
|
:style="{ backgroundColor: color }"
|
||
|
><check-outlined /></span
|
||
|
></template>
|
||
|
</div>
|
||
|
</a-drawer> -->
|
||
|
</a-layout-header>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts">
|
||
|
import { defineComponent, ref, watch, computed, getCurrentInstance } from 'vue';
|
||
|
import { useRouter } from 'vue-router';
|
||
|
import { message } from 'ant-design-vue';
|
||
|
import { Cookies } from '/nerv-lib/util/cookie';
|
||
|
import { getLocalSetting, setLocalSetting, http } from '/nerv-lib/saas';
|
||
|
import { appConfigStore } from '/nerv-lib/saas/store/modules/app-config';
|
||
|
import { useTags } from '/nerv-base/store/modules/tags';
|
||
|
import { authorizationService } from '/nerv-base/store/modules/authorization-service';
|
||
|
import { replaceStyleVariables } from 'vite-plugin-theme/es/client';
|
||
|
import { getThemeColors } from '../../../../../build/themeConfig';
|
||
|
import { SettingOutlined, CheckOutlined } from '@ant-design/icons-vue';
|
||
|
import { messagecount } from '/nerv-lib/saas/store/modules/messagecount';
|
||
|
import { storeToRefs } from 'pinia';
|
||
|
export default defineComponent({
|
||
|
name: 'NsHeader',
|
||
|
components: {
|
||
|
SettingOutlined,
|
||
|
CheckOutlined,
|
||
|
},
|
||
|
props: {
|
||
|
// eslint-disable-next-line vue/require-valid-default-prop
|
||
|
headerList: { type: Array, default: [] },
|
||
|
initHeaderKey: { type: Array },
|
||
|
},
|
||
|
setup: (props: any) => {
|
||
|
const configStore = appConfigStore();
|
||
|
const { getThemeConfig: themeConfig } = storeToRefs(configStore);
|
||
|
const { getHeaderBellInfo: headerBellInfo } = storeToRefs(configStore);
|
||
|
const messagecountStore = messagecount();
|
||
|
const bellInfo = ref();
|
||
|
// const messageCount = ref();
|
||
|
const time = ref();
|
||
|
const toCustomUrl = (val: string) => {
|
||
|
window.open(`${val}?nervsid=${Cookies.get('nervsid')}`);
|
||
|
// window.location.href = `${val}?nervsid=${Cookies.get('nervsid')}`;
|
||
|
};
|
||
|
const messageCount = computed(() => {
|
||
|
return messagecountStore.getCount;
|
||
|
});
|
||
|
bellInfo.value = configStore.headerBellInfo;
|
||
|
if (bellInfo.value.isShow) {
|
||
|
async function initMessageCount() {
|
||
|
try {
|
||
|
const res = await http.get(bellInfo.value.api);
|
||
|
if (res.success) {
|
||
|
messagecountStore.updateCount(
|
||
|
(bellInfo.value.dealData ? bellInfo.value.dealData(res) : res.data.count) > 99
|
||
|
? '99+'
|
||
|
: bellInfo.value.dealData
|
||
|
? bellInfo.value.dealData(res)
|
||
|
: res.data.count,
|
||
|
);
|
||
|
}
|
||
|
} catch (err) {}
|
||
|
}
|
||
|
if (!configStore?.customInitMessageCount) {
|
||
|
initMessageCount();
|
||
|
time.value = setInterval(initMessageCount, 10000);
|
||
|
}
|
||
|
}
|
||
|
const userName = ref<string>('-');
|
||
|
const authorizationStore = authorizationService();
|
||
|
|
||
|
const initUserInfo = window.sessionStorage['userInfo'];
|
||
|
if (!authorizationStore.getProjectName && Cookies.get('projectName')) {
|
||
|
authorizationStore.setProjectName(Cookies.get('projectName'));
|
||
|
}
|
||
|
if (!authorizationStore.getEnterpriseName && window.sessionStorage['userInfo']) {
|
||
|
const userInfo = JSON.parse(window.sessionStorage['userInfo']);
|
||
|
authorizationStore.setEnterpriseName(
|
||
|
!userInfo.organizationalName ? '' : userInfo.organizationalName,
|
||
|
);
|
||
|
}
|
||
|
const projectName = computed(() => authorizationStore.getProjectName);
|
||
|
const enterpriseName = computed(() => authorizationStore.getEnterpriseName);
|
||
|
initUserInfo
|
||
|
? (userName.value = JSON.parse(initUserInfo).accountRealName
|
||
|
? JSON.parse(initUserInfo).accountRealName
|
||
|
: JSON.parse(initUserInfo).accountName)
|
||
|
: '';
|
||
|
const menuList = ref([]);
|
||
|
const subMenuList = ref([]);
|
||
|
const router = useRouter();
|
||
|
const tochildren = (val) => {
|
||
|
if (val.children === undefined || val.children.length === 0) {
|
||
|
router.push({
|
||
|
name: val.name,
|
||
|
});
|
||
|
} else {
|
||
|
for (var i = 0; i < val.children.length; i++) {
|
||
|
if (!val.children[i].isHide) {
|
||
|
tochildren(val.children[i]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
const getOPMenu = (list) => {
|
||
|
if (configStore.enablePermissions !== undefined && configStore.enablePermissions) {
|
||
|
return list.filter((item) => {
|
||
|
return authorizationStore.checkPermission(item.code);
|
||
|
});
|
||
|
} else {
|
||
|
return list;
|
||
|
}
|
||
|
};
|
||
|
const checkMenus = (list) => {
|
||
|
if (configStore.enablePermissions !== undefined && configStore.enablePermissions) {
|
||
|
return list.filter((item) => {
|
||
|
return authorizationStore.checkAllPermission(item.code);
|
||
|
});
|
||
|
} else {
|
||
|
return list;
|
||
|
}
|
||
|
};
|
||
|
props.headerList.forEach((item) => {
|
||
|
if (!item.isHide) {
|
||
|
if (!item.meta.isNewOpen) {
|
||
|
menuList.value.push(item);
|
||
|
} else {
|
||
|
subMenuList.value.push(item);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
watch(
|
||
|
() => props.headerList,
|
||
|
(e) => {
|
||
|
menuList.value = [];
|
||
|
subMenuList.value = [];
|
||
|
e.forEach((item) => {
|
||
|
if (!item.isHide) {
|
||
|
if (!item.meta.isNewOpen) {
|
||
|
menuList.value.push(item);
|
||
|
} else {
|
||
|
subMenuList.value.push(item);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
{ deep: true },
|
||
|
);
|
||
|
const toUpdate = () => {
|
||
|
router.push({
|
||
|
name: 'UpdatePassWord',
|
||
|
});
|
||
|
};
|
||
|
const backMessage = () => {
|
||
|
if (headerBellInfo.value.toRouterName) {
|
||
|
router.push({
|
||
|
name: headerBellInfo.value.toRouterName,
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const dropOut = () => {
|
||
|
message.loading('正在退出', 0.1);
|
||
|
if (configStore.dropOut) {
|
||
|
configStore.dropOut(Cookies, router, useTags, authorizationStore, http);
|
||
|
} else {
|
||
|
Cookies.remove('nervsid');
|
||
|
sessionStorage.clear();
|
||
|
router.push('/login');
|
||
|
useTags().clearTags();
|
||
|
authorizationStore.clearAuthorization();
|
||
|
}
|
||
|
};
|
||
|
const updatePassWord = () => {
|
||
|
router.push('/synthetical/user/updatePassWord');
|
||
|
};
|
||
|
const currentThemeColor = ref(null);
|
||
|
function changeTheme(color: string) {
|
||
|
replaceStyleVariables({ colorVariables: [...getThemeColors(color)] });
|
||
|
currentThemeColor.value = color;
|
||
|
setLocalSetting({ themeColor: color });
|
||
|
}
|
||
|
|
||
|
const appConfig = getCurrentInstance()?.appContext.config.globalProperties.$appConfig;
|
||
|
const themeColor = getLocalSetting()?.themeColor || appConfig?.themeColor;
|
||
|
|
||
|
if (themeColor) {
|
||
|
changeTheme(themeColor);
|
||
|
}
|
||
|
|
||
|
const settingVisible = ref<boolean>(false);
|
||
|
function changeSettingVisible(visible: boolean) {
|
||
|
settingVisible.value = visible;
|
||
|
}
|
||
|
const themeColorList = [
|
||
|
'#37abc4',
|
||
|
'#1677FF',
|
||
|
'#009688',
|
||
|
'#536dfe',
|
||
|
'#ff5c93',
|
||
|
'#ee4f12',
|
||
|
'#0096c7',
|
||
|
'#9c27b0',
|
||
|
'#ff9800',
|
||
|
];
|
||
|
const backDoor = () => {
|
||
|
let protocol = window.location.protocol;
|
||
|
const nervsid = Cookies.get('nervsid');
|
||
|
http.get('/portalurl.json').then((res) => {
|
||
|
if (nervsid) {
|
||
|
window.location.href = `${protocol}//${res.url}report?nervsid=${nervsid}`;
|
||
|
} else {
|
||
|
window.location.href = `${protocol}//${res.url}report`;
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
return {
|
||
|
themeConfig,
|
||
|
backDoor,
|
||
|
themeColorList,
|
||
|
currentThemeColor,
|
||
|
settingVisible,
|
||
|
changeSettingVisible,
|
||
|
checkMenus,
|
||
|
toCustomUrl,
|
||
|
time,
|
||
|
messageCount,
|
||
|
backMessage,
|
||
|
bellInfo,
|
||
|
showProject: configStore.showProject,
|
||
|
projectName,
|
||
|
enterpriseName,
|
||
|
tochildren,
|
||
|
menuList,
|
||
|
toUpdate,
|
||
|
subMenuList,
|
||
|
changeTheme,
|
||
|
userName,
|
||
|
dropOut,
|
||
|
updatePassWord,
|
||
|
getOPMenu,
|
||
|
configStore,
|
||
|
};
|
||
|
},
|
||
|
beforeUnmount() {
|
||
|
clearInterval(this.time);
|
||
|
},
|
||
|
});
|
||
|
</script>
|
||
|
|
||
|
<style lang="less" scoped>
|
||
|
.theme-picker {
|
||
|
display: flex;
|
||
|
flex-wrap: wrap;
|
||
|
margin: 16px 0;
|
||
|
justify-content: space-around;
|
||
|
|
||
|
.theme-picker_item {
|
||
|
display: flex;
|
||
|
justify-content: center;
|
||
|
align-items: center;
|
||
|
width: 20px;
|
||
|
height: 20px;
|
||
|
cursor: pointer;
|
||
|
border: 1px solid #ddd;
|
||
|
border-radius: 2px;
|
||
|
|
||
|
span {
|
||
|
display: none;
|
||
|
font-size: 12px;
|
||
|
color: #fff;
|
||
|
}
|
||
|
|
||
|
&.current span {
|
||
|
display: flex;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
:deep(.ant-menu-submenu-title) {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
}
|
||
|
:deep(.header-menu .ant-menu-title-content) {
|
||
|
div {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
.ns-icon {
|
||
|
margin-right: 7px;
|
||
|
transform: translateY(2px);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
:deep(.ant-menu-submenu-title .ant-menu-title-content) {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
.ns-icon {
|
||
|
margin-right: 7px;
|
||
|
transform: translateY(2px);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.header {
|
||
|
padding: 0;
|
||
|
position: fixed;
|
||
|
top: 0;
|
||
|
z-index: 505;
|
||
|
width: 100%;
|
||
|
background-image: url(/asset/image/header.png);
|
||
|
background-size: 100% 100%;
|
||
|
}
|
||
|
|
||
|
:deep(.ant-badge-count) {
|
||
|
// width: 16px;
|
||
|
height: 16px;
|
||
|
line-height: 8px;
|
||
|
text-align: center;
|
||
|
padding: 4px;
|
||
|
// line-height: 16px;
|
||
|
// background: #ec4d28;
|
||
|
border-radius: 8px;
|
||
|
box-shadow: 0 0 0 0px #fff;
|
||
|
transform: translate(55%, -10%);
|
||
|
}
|
||
|
|
||
|
:deep(.hiden) {
|
||
|
opacity: 0 !important;
|
||
|
position: absolute;
|
||
|
user-select: none;
|
||
|
width: 1px !important;
|
||
|
height: 1px !important;
|
||
|
}
|
||
|
|
||
|
.header-menu {
|
||
|
width: calc(100% - @layout-sider-width - 208px);
|
||
|
.ant-menu-root {
|
||
|
background-color: transparent;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.logo {
|
||
|
width: calc(@layout-sider-width - 16px);
|
||
|
min-width: @layout-sider-width !important;
|
||
|
display: flex;
|
||
|
padding-left: 16px;
|
||
|
align-items: center;
|
||
|
|
||
|
img {
|
||
|
width: 100%;
|
||
|
}
|
||
|
|
||
|
// .headerLogin {
|
||
|
// width: @layout-sider-width;
|
||
|
// height: 48px;
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
.ant-layout-header {
|
||
|
display: flex;
|
||
|
padding: 0 !important;
|
||
|
}
|
||
|
|
||
|
.nsHeader_action {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
padding-left: 16px;
|
||
|
padding-right: 16px;
|
||
|
width: 208px;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
justify-content: right;
|
||
|
|
||
|
.action {
|
||
|
cursor: pointer;
|
||
|
|
||
|
&:hover {
|
||
|
background-color: @layout-header-hover;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.projectName {
|
||
|
white-space: nowrap;
|
||
|
}
|
||
|
|
||
|
.bells,
|
||
|
.setting {
|
||
|
height: 100%;
|
||
|
// width: 50px;
|
||
|
padding-left: 12px;
|
||
|
padding-right: 12px;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
justify-content: center;
|
||
|
}
|
||
|
|
||
|
.projectName {
|
||
|
color: rgba(255, 255, 255, 0.9);
|
||
|
white-space: nowrap;
|
||
|
padding-left: 10px;
|
||
|
padding-right: 10px;
|
||
|
}
|
||
|
|
||
|
// padding-right: 30px;
|
||
|
.dropOut {
|
||
|
height: 100%;
|
||
|
padding-right: 16px;
|
||
|
padding-left: 16px;
|
||
|
}
|
||
|
|
||
|
.userName {
|
||
|
line-height: 48px;
|
||
|
display: flex;
|
||
|
white-space: nowrap;
|
||
|
align-items: center;
|
||
|
cursor: pointer;
|
||
|
padding-left: 10px;
|
||
|
padding-right: 10px;
|
||
|
height: 100%;
|
||
|
}
|
||
|
|
||
|
.headerAdminIcon {
|
||
|
margin-right: 8px;
|
||
|
}
|
||
|
.downArrow {
|
||
|
margin-left: 8px;
|
||
|
}
|
||
|
|
||
|
span {
|
||
|
user-select: none;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.menuItem {
|
||
|
height: 80px;
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
}
|
||
|
:deep(.ant-menu-horizontal) {
|
||
|
border: unset !important;
|
||
|
}
|
||
|
:deep(.ant-menu-item-selected) {
|
||
|
background: @primary-color;
|
||
|
}
|
||
|
</style>
|