|
|
|
|
<template>
|
|
|
|
|
<div class="module-portal">
|
|
|
|
|
<header class="portal-header">
|
|
|
|
|
<div class="portal-header-inner">
|
|
|
|
|
<div class="portal-header-left" @click="goPortal">
|
|
|
|
|
<img :src="logoImg" alt="logo" class="portal-logo" />
|
|
|
|
|
<h1 class="portal-title">{{ websiteName }}</h1>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="portal-header-right">
|
|
|
|
|
<span class="portal-time">{{ currentTime }}</span>
|
|
|
|
|
<span class="portal-user"><UserOutlined /> {{ userName }}</span>
|
|
|
|
|
<a class="portal-logout" @click="handleLogout"><LogoutOutlined /> 退出</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<main class="portal-main">
|
|
|
|
|
<div class="portal-bg-decor">
|
|
|
|
|
<div class="portal-grid"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="portal-container">
|
|
|
|
|
<div class="portal-section-head">
|
|
|
|
|
<div class="portal-section-bar"></div>
|
|
|
|
|
<h2>业务导航</h2>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="portal-modules">
|
|
|
|
|
<div
|
|
|
|
|
v-for="item in portalModules"
|
|
|
|
|
:key="item.name"
|
|
|
|
|
class="portal-module-card"
|
|
|
|
|
@click="enterModule(item.menu)"
|
|
|
|
|
>
|
|
|
|
|
<div class="portal-module-icon">
|
|
|
|
|
<component :is="$antIcons[item.menu?.icon || item.icon]" />
|
|
|
|
|
</div>
|
|
|
|
|
<div class="portal-module-body">
|
|
|
|
|
<h3>{{ item.name }}</h3>
|
|
|
|
|
<span class="portal-module-link">进入模块 <RightOutlined /></span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</main>
|
|
|
|
|
|
|
|
|
|
<footer class="portal-footer">
|
|
|
|
|
<span>内部平台,严禁外传</span>
|
|
|
|
|
</footer>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
|
|
|
|
import { useRouter } from 'vue-router';
|
|
|
|
|
import dayjs from 'dayjs';
|
|
|
|
|
import { Modal, message } from 'ant-design-vue';
|
|
|
|
|
import { LogoutOutlined, RightOutlined, UserOutlined } from '@ant-design/icons-vue';
|
|
|
|
|
import logoImg from '/@/assets/images/logo/smart-admin-logo.png';
|
|
|
|
|
import { PORTAL_SUB_PAGE_PATH } from '/@/constants/system/portal-const';
|
|
|
|
|
import { useAppConfigStore } from '/@/store/modules/system/app-config';
|
|
|
|
|
import { usePortalModuleStore } from '/@/store/modules/system/portal-module';
|
|
|
|
|
import { useUserStore } from '/@/store/modules/system/user';
|
|
|
|
|
import { loginApi } from '/@/api/system/login-api';
|
|
|
|
|
import {
|
|
|
|
|
buildPortalModules,
|
|
|
|
|
findFirstLeafMenu,
|
|
|
|
|
getModuleSubEntries,
|
|
|
|
|
} from '/@/utils/portal-menu-util';
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
const userStore = useUserStore();
|
|
|
|
|
const portalStore = usePortalModuleStore();
|
|
|
|
|
const appConfigStore = useAppConfigStore();
|
|
|
|
|
|
|
|
|
|
const websiteName = computed(() => appConfigStore.websiteName);
|
|
|
|
|
const userName = computed(() => userStore.actualName || userStore.loginName || '用户');
|
|
|
|
|
const portalModules = computed(() => buildPortalModules(userStore.getMenuTree || []));
|
|
|
|
|
|
|
|
|
|
const currentTime = ref('');
|
|
|
|
|
let timer = null;
|
|
|
|
|
|
|
|
|
|
function updateTime() {
|
|
|
|
|
const now = dayjs();
|
|
|
|
|
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
|
|
|
|
currentTime.value = `${now.format('YYYY-MM-DD HH:mm:ss')} ${weekDays[now.day()]}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function goPortal() {
|
|
|
|
|
portalStore.clearActiveModule();
|
|
|
|
|
router.push('/portal');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function pushMenuPath(menu) {
|
|
|
|
|
if (!menu?.path) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
router.push(menu.path.startsWith('/') ? menu.path : `/${menu.path}`);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function enterModule(module) {
|
|
|
|
|
if (!module) {
|
|
|
|
|
message.warning('您暂无该模块权限');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
portalStore.setActiveModule(module.menuId);
|
|
|
|
|
|
|
|
|
|
if (isTopLeafModule(module)) {
|
|
|
|
|
pushMenuPath(module);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const entries = getModuleSubEntries(module);
|
|
|
|
|
if (!entries.length) {
|
|
|
|
|
message.warning('该模块暂无可用菜单');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entries.length === 1) {
|
|
|
|
|
const leaf = findFirstLeafMenu(entries) || entries[0];
|
|
|
|
|
if (pushMenuPath(leaf)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
router.push({
|
|
|
|
|
path: PORTAL_SUB_PAGE_PATH,
|
|
|
|
|
query: { moduleId: module.menuId },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isTopLeafModule(module) {
|
|
|
|
|
return !!module.path && (!module.children || module.children.length === 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleLogout() {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: '确定退出系统吗?',
|
|
|
|
|
okText: '确定',
|
|
|
|
|
cancelText: '取消',
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
try {
|
|
|
|
|
await loginApi.logout();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
portalStore.clearActiveModule();
|
|
|
|
|
userStore.logout();
|
|
|
|
|
router.push('/login');
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
portalStore.clearActiveModule();
|
|
|
|
|
userStore.resetBusinessNavigation();
|
|
|
|
|
updateTime();
|
|
|
|
|
timer = setInterval(updateTime, 1000);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
if (timer) {
|
|
|
|
|
clearInterval(timer);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
@import './portal-common.less';
|
|
|
|
|
</style>
|