init: UserBaseFront (frontend)

This commit is contained in:
chenxing
2026-08-10 14:41:13 +08:00
commit eea881b616
174 changed files with 32833 additions and 0 deletions
+194
View File
@@ -0,0 +1,194 @@
<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>