Files
userbase/src/App.vue
T

195 lines
5.8 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.
<script setup lang="ts">
import { ref, onMounted, reactive, provide, computed } from "vue";
import layout from "./components/layout.vue";
import { CurrentRole, LayoutData } from "./types/Basics";
import { useRouter } from "vue-router";
import config from "@/assets/config/host.config";
import { useDefaultStore } from "@/store/index.js";
import Apis from '@/api/index'
import { alovaInstance } from "@/utils/alova/alova-iview";
import useCurrentInstance from "@/utils/hook/useCurrentInstance";
import { UserRoleEnum } from "./types";
const store = useDefaultStore();
const router = useRouter();
const { $bus } = useCurrentInstance();
const refLayout = useTemplateRef('refLayout');
const isRouterAlive = ref(true),
isLogin = ref(false),
isNoAuthority = ref(false);
// 当前登录用户,供 resetMenuPath 事件复用
const currentUser = ref<any>(null);
const layoutData: LayoutData = reactive({
isAlone: false,
appName: null,
appList: [],
modList: [],
userInfo: null,
baseHost: null,
ssoHost: null,
});
const reload = () => {
isRouterAlive.value = false;
setTimeout(() => {
isRouterAlive.value = true;
}, 0);
};
provide("reload", reload);
const layoutInit = (info: any, modList: any[], appList: Array<any>, baseHost: string, ssoHost: string) => {
layoutData.appName = "系统管理";
layoutData.baseHost = baseHost;
layoutData.ssoHost = ssoHost;
let { id, name, profilePicture } = info;
layoutData.modList = modList || [];
// 有子菜单时不算「单模块独占」模式,需展示左侧菜单
const hasChildren = modList.some((m: any) => m.children && m.children.length > 0);
layoutData.isAlone = modList.length <= 1 && !hasChildren;
layoutData.userInfo = { id, name, avatar: profilePicture };
layoutData.appList = appList || [];
};
/**
* 角色判定
* 现基于 GetUserInfo 返回的 user.type 判定角色:
* type=1 → SuperAdmin,type=2 → School(不再有 Teacher 角色)
* 同时写入 currentRole 供下游 Utils.getCurrentRoleInfo 读取(保持兼容)
*/
const setCurrentRole = (user: any) => {
const userId = user?.id ?? null;
const roleId = user?.type ?? null;
const currentRole: CurrentRole = {
childId: null,
roleId,
schId: null,
userId,
};
localStorage.setItem("currentRole", encodeURI(JSON.stringify(currentRole)));
// 主题样式已本地化到 src/assets/styles/layout.css(含 default-theme / base.layout.beta / _iview_override),不再请求远程样式
if (user?.type === 1) {
store.setUserRole(UserRoleEnum.SuperAdmin);
} else {
// type=2 或其他 → School(默认)
store.setUserRole(UserRoleEnum.School);
}
};
onMounted(async () => {
const { baseHost, ssoHost } = config;
try {
var user: any = await alovaInstance.Request(Apis.Base.getUserInfo());
// 系统字典 & 模块列表(模块当前写死,后续接入接口)
await store.fetchSysDict();
await store.fetchModules();
currentUser.value = user;
setCurrentRole(user);
layoutInit(user, store.modules, store.modules, baseHost, ssoHost);
// 登录后直接跳转到左侧菜单第一个可用入口
// (顶层可能是单页,如「组,用户管理」;也可能是分组,取其首个子项)
// 仅在用户处于根路径时才跳转,避免刷新业务页(如 /app-manage/list)被强制拉回
const firstModule = store.modules[0];
const firstPage = firstModule?.children?.length
? firstModule.children[0].page
: firstModule?.page;
if (firstPage && router.currentRoute.value.path === "/") {
router.replace(firstPage);
}
isLogin.value = true;
} catch (error) {
console.log(error);
if (error != "redirect") Message.error("载入用户信息失败!");
}
});
const getRouterKey: (route: any) => string = route => {
let str = route?.name;
// if (str === "clocklist") str += "-" + route.params.id;
return str;
};
/**
* 需要被 keep-alive 缓存的组件名(按路由 meta.keepAlive 推导)。
* include 按组件 name 匹配,因此对应页面需 defineOptions({ name }) 与之相等。
*/
const cachedNames = computed(() =>
router.getRoutes().filter((r: any) => r.meta?.keepAlive).map((r: any) => r.name as string)
);
</script>
<template>
<layout ref="refLayout" v-if="isLogin" :layoutData="layoutData"></layout>
<div v-if="isLogin" :class="['base-wrap-main', layoutData.isAlone ? 'alone-page' : '']">
<template v-if="!isNoAuthority">
<router-view v-if="!!isRouterAlive" v-slot="{ Component, route }">
<transition name="fade" mode="out-in">
<keep-alive :include="cachedNames">
<component :is="Component" :key="getRouterKey(route)" />
</keep-alive>
</transition>
</router-view>
</template>
<div v-else class="no-authority-wrap">
<h3>暂无权限</h3>
<h6>如需查看,请联络管理员为您分配权限</h6>
</div>
</div>
</template>
<style lang="scss">
/* 开始过渡阶段,动画出去阶段 */
.fade-enter-active,
.fade-leave-active {
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
}
/* 进入开始 */
.fade-enter {
// transform: translateY(10px);
opacity: 0;
}
/* 出去终点 */
.fade-leave-active {
// transform: translateY(-10px);
// opacity: 0;
}
.back-enter-active,
.back-leave-active {
transition: all 1ms cubic-bezier(0, 0.99, 1, 0.03);
}
/* 进入开始 */
.back-enter {
display: none;
}
/* 出去终点 */
.back-leave-active {
display: none;
}
#app {
height: 100%;
}
.base-wrap-main .main-wrapper {
height: 100%;
}
</style>