refactor: 项目重构

This commit is contained in:
Ray.Hao
2025-05-24 07:35:46 +08:00
parent cfe041d7d2
commit 32686ad807
51 changed files with 1201 additions and 696 deletions

View File

@@ -5,73 +5,178 @@ import router from "@/router";
import { usePermissionStore, useUserStore } from "@/store";
import { ROLE_ROOT } from "@/constants";
// 路由生成锁,防止重复生成
let isGeneratingRoutes = false;
export function setupPermission() {
// 白名单路由
const whiteList = ["/login"];
router.beforeEach(async (to, from, next) => {
NProgress.start();
console.log("to.path", to.path);
console.log("🚀 Route guard triggered:", { to: to.path, from: from.path });
const isLogin = Auth.isLoggedIn();
if (isLogin) {
const isLoggedIn = Auth.isLoggedIn();
if (isLoggedIn) {
console.log("✅ User is logged in");
// 如果已登录但访问登录页,重定向到首页
if (to.path === "/login") {
// 如果已登录,跳转到首页
console.log("🔄 Redirecting from login to home");
next({ path: "/" });
} else {
// 未登录
const permissionStore = usePermissionStore();
// 判断路由是否加载完成
if (permissionStore.routesLoaded) {
if (to.matched.length === 0) {
// 路由未匹配跳转到404
next("/404");
} else {
// 动态设置页面标题
const title = (to.params.title as string) || (to.query.title as string);
if (title) {
to.meta.title = title;
}
next();
}
} else {
try {
// 生成路由
const dynamicRoutes = await permissionStore.generateRoutes();
dynamicRoutes.forEach((route: RouteRecordRaw) => router.addRoute(route));
next({ ...to, replace: true });
} catch (error) {
console.error(error);
// 路由加载失败,重置 token 并重定向到登录页
await useUserStore().resetAllState();
redirectToLogin(to, next);
NProgress.done();
}
}
return;
}
// 处理已登录用户的路由访问
await handleAuthenticatedUser(to, from, next);
} else {
// 未登录,判断是否在白名单中
console.log("❌ User not logged in");
// 未登录用户的处理
if (whiteList.includes(to.path)) {
next();
} else {
// 不在白名单,重定向到登录页
redirectToLogin(to, next);
NProgress.done();
}
}
});
// 后置守卫,保证每次路由跳转结束时关闭进度条
router.afterEach(() => {
// 后置守卫,保进度条关闭
router.afterEach((to, from) => {
console.log("✅ Route navigation completed:", { to: to.path, from: from.path });
NProgress.done();
});
}
// 重定向到登录页
/**
* 处理已登录用户的路由访问
*/
async function handleAuthenticatedUser(
to: RouteLocationNormalized,
from: RouteLocationNormalized,
next: NavigationGuardNext
) {
const permissionStore = usePermissionStore();
const userStore = useUserStore();
try {
// 检查用户信息是否存在
if (!userStore.userInfo.username) {
console.log("🔄 User info not found, fetching...");
await userStore.getUserInfo();
}
// 检查路由是否已生成
if (!permissionStore.routesLoaded) {
console.log("🔄 Routes not loaded, generating...");
// 防止重复生成路由
if (isGeneratingRoutes) {
console.log("⏳ Routes already generating, waiting...");
// 等待当前路由生成完成
await waitForRoutesGeneration(permissionStore);
} else {
await generateAndAddRoutes(permissionStore);
}
// 路由生成完成后,重新导航到目标路由
console.log("🔄 Routes generated, redirecting to:", to.path);
next({ ...to, replace: true });
return;
}
// 路由已加载,检查路由是否存在
if (to.matched.length === 0) {
console.log("❌ Route not found, redirecting to 404");
next("/404");
return;
}
// 动态设置页面标题
const title = (to.params.title as string) || (to.query.title as string);
if (title) {
to.meta.title = title;
}
console.log("✅ Route access granted:", to.path);
next();
} catch (error) {
console.error("❌ Route guard error:", error);
// 出错时重置状态并重定向到登录页
await resetUserStateAndRedirect(to, next);
}
}
/**
* 生成并添加动态路由
*/
async function generateAndAddRoutes(permissionStore: any) {
isGeneratingRoutes = true;
try {
console.log("🔧 Generating dynamic routes...");
const dynamicRoutes = await permissionStore.generateRoutes();
// 添加路由到路由器
dynamicRoutes.forEach((route: RouteRecordRaw) => {
router.addRoute(route);
});
console.log("✅ All dynamic routes generated and added");
} finally {
isGeneratingRoutes = false;
}
}
/**
* 等待路由生成完成
*/
async function waitForRoutesGeneration(permissionStore: any): Promise<void> {
return new Promise((resolve) => {
const checkInterval = setInterval(() => {
if (!isGeneratingRoutes && permissionStore.routesLoaded) {
clearInterval(checkInterval);
resolve();
}
}, 50); // 每50ms检查一次
// 超时保护最多等待5秒
setTimeout(() => {
clearInterval(checkInterval);
console.warn("⚠️ Routes generation timeout");
resolve();
}, 5000);
});
}
/**
* 重置用户状态并重定向到登录页
*/
async function resetUserStateAndRedirect(to: RouteLocationNormalized, next: NavigationGuardNext) {
try {
await useUserStore().resetAllState();
redirectToLogin(to, next);
} catch (resetError) {
console.error("❌ Failed to reset user state:", resetError);
// 强制跳转到登录页
next("/login");
} finally {
NProgress.done();
}
}
/**
* 重定向到登录页
*/
function redirectToLogin(to: RouteLocationNormalized, next: NavigationGuardNext) {
const params = new URLSearchParams(to.query as Record<string, string>);
const queryString = params.toString();
const redirect = queryString ? `${to.path}?${queryString}` : to.path;
console.log("🔄 Redirecting to login with redirect:", redirect);
next(`/login?redirect=${encodeURIComponent(redirect)}`);
}

View File

@@ -1,8 +1,29 @@
import { useDictSync } from "@/composables/useDictSync";
import { Auth } from "@/utils/auth";
import { useUserStore } from "@/store";
import { watch } from "vue";
// 全局 WebSocket 实例管理
const websocketInstances = new Map<string, any>();
// 用于防止重复初始化的状态标记
let isInitialized = false;
let dictWebSocketInstance: ReturnType<typeof useDictSync> | null = null;
/**
* 注册 WebSocket 实例
*/
export function registerWebSocketInstance(key: string, instance: any) {
websocketInstances.set(key, instance);
console.log(`[WebSocketPlugin] Registered WebSocket instance: ${key}`);
}
/**
* 获取 WebSocket 实例
*/
export function getWebSocketInstance(key: string) {
return websocketInstances.get(key);
}
/**
* 初始化WebSocket服务
@@ -34,19 +55,27 @@ export function setupWebSocket() {
try {
// 延迟初始化,确保应用完全启动
setTimeout(() => {
const dictWebSocket = useDictSync();
// 保存实例引用
dictWebSocketInstance = useDictSync();
registerWebSocketInstance("dictSync", dictWebSocketInstance);
// 初始化字典WebSocket服务
dictWebSocket.initWebSocket();
dictWebSocketInstance.initWebSocket();
console.log("[WebSocketPlugin] 字典WebSocket初始化完成");
// 在窗口关闭前断开WebSocket连接
window.addEventListener("beforeunload", () => {
console.log("[WebSocketPlugin] 窗口即将关闭断开WebSocket连接");
dictWebSocket.closeWebSocket();
isInitialized = false;
// 初始化在线用户计数WebSocket
import("@/composables/useOnlineCount").then(({ useOnlineCount }) => {
const onlineCountInstance = useOnlineCount({ autoInit: false });
onlineCountInstance.initWebSocket();
console.log("[WebSocketPlugin] 在线用户计数WebSocket初始化完成");
});
// 在窗口关闭前断开WebSocket连接
window.addEventListener("beforeunload", handleWindowClose);
// 监听用户注销事件
watchUserLogout();
console.log("[WebSocketPlugin] WebSocket服务初始化完成");
isInitialized = true;
}, 1000); // 延迟1秒初始化
@@ -54,3 +83,84 @@ export function setupWebSocket() {
console.error("[WebSocketPlugin] 初始化WebSocket服务失败:", error);
}
}
/**
* 处理窗口关闭
*/
function handleWindowClose() {
console.log("[WebSocketPlugin] 窗口即将关闭断开WebSocket连接");
cleanupWebSocket();
}
/**
* 监听用户注销
*/
function watchUserLogout() {
const userStore = useUserStore();
// 监听用户信息变化,当用户信息被清空时断开连接
watch(
() => userStore.userInfo,
(newUserInfo, oldUserInfo) => {
// 从有用户信息变为无用户信息,说明用户注销了
if (oldUserInfo?.username && !newUserInfo?.username) {
console.log("[WebSocketPlugin] 检测到用户注销断开WebSocket连接");
cleanupWebSocket();
}
},
{ deep: true }
);
}
/**
* 清理WebSocket连接
*/
export function cleanupWebSocket() {
// 清理字典 WebSocket
if (dictWebSocketInstance) {
try {
dictWebSocketInstance.closeWebSocket();
console.log("[WebSocketPlugin] 字典WebSocket连接已断开");
} catch (error) {
console.error("[WebSocketPlugin] 断开字典WebSocket连接失败:", error);
}
}
// 清理所有注册的 WebSocket 实例
websocketInstances.forEach((instance, key) => {
try {
if (instance && typeof instance.disconnect === "function") {
instance.disconnect();
console.log(`[WebSocketPlugin] ${key} WebSocket连接已断开`);
} else if (instance && typeof instance.closeWebSocket === "function") {
instance.closeWebSocket();
console.log(`[WebSocketPlugin] ${key} WebSocket连接已断开`);
}
} catch (error) {
console.error(`[WebSocketPlugin] 断开 ${key} WebSocket连接失败:`, error);
}
});
// 清空实例映射
websocketInstances.clear();
// 移除事件监听器
window.removeEventListener("beforeunload", handleWindowClose);
// 重置状态
dictWebSocketInstance = null;
isInitialized = false;
}
/**
* 重新初始化WebSocket用于登录后重连
*/
export function reinitializeWebSocket() {
// 先清理现有连接
cleanupWebSocket();
// 延迟后重新初始化
setTimeout(() => {
setupWebSocket();
}, 500);
}