refactor: ♻️ 提取 ROLE_ROOT 常量到 constants 目录并全局统一引用
This commit is contained in:
@@ -94,7 +94,7 @@ const noticeList = ref<NoticePageVO[]>([]);
|
||||
const noticeDialogVisible = ref(false);
|
||||
const noticeDetail = ref<NoticeDetailVO | null>(null);
|
||||
|
||||
import { useStomp } from "@/hooks/websocket/core/useStomp";
|
||||
import { useStomp } from "@/composables/useStomp";
|
||||
const { subscribe, unsubscribe, isConnected } = useStomp();
|
||||
|
||||
watch(
|
||||
|
||||
11
src/composables/index.ts
Normal file
11
src/composables/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 全局组合式函数入口文件
|
||||
* 导出所有可用的组合式函数
|
||||
*/
|
||||
|
||||
// 导出核心组合式函数
|
||||
export { useStomp } from "./useStomp";
|
||||
|
||||
// 导出业务服务组合式函数
|
||||
export { useDictSync } from "./useDictSync";
|
||||
export { useOnlineCount } from "./useOnlineCount";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useDictStoreHook } from "@/store/modules/dict.store";
|
||||
import { useStomp } from "../core/useStomp";
|
||||
import { useStomp } from "./useStomp";
|
||||
import { IMessage } from "@stomp/stompjs";
|
||||
import { ref } from "vue";
|
||||
|
||||
@@ -16,7 +16,7 @@ export type DictMessageCallback = (_message: DictMessage) => void;
|
||||
let instance: ReturnType<typeof createDictSyncHook> | null = null;
|
||||
|
||||
/**
|
||||
* 创建字典同步Hook
|
||||
* 创建字典同步组合式函数
|
||||
* 负责监听后端字典变更并同步到前端
|
||||
*/
|
||||
function createDictSyncHook() {
|
||||
@@ -186,7 +186,7 @@ function createDictSyncHook() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典同步Hook
|
||||
* 字典同步组合式函数
|
||||
* 用于监听后端字典变更并同步到前端
|
||||
*/
|
||||
export function useDictSync() {
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ref, onMounted, onUnmounted, watch } from "vue";
|
||||
import { useStomp } from "../core/useStomp";
|
||||
import { useStomp } from "./useStomp";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Storage } from "@/utils/storage";
|
||||
import { ACCESS_TOKEN_KEY } from "@/constants/cache-keys";
|
||||
|
||||
/**
|
||||
* 在线用户计数Hook
|
||||
* 在线用户计数组合式函数
|
||||
* 用于订阅后端推送的在线用户数量变化
|
||||
*/
|
||||
export function useOnlineCount() {
|
||||
@@ -23,7 +23,7 @@ export interface UseStompOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* STOMP WebSocket连接Hook
|
||||
* STOMP WebSocket连接组合式函数
|
||||
* 用于管理WebSocket连接的建立、断开、重连和消息订阅
|
||||
*/
|
||||
export function useStomp(options: UseStompOptions = {}) {
|
||||
@@ -244,70 +244,73 @@ export function useStomp(options: UseStompOptions = {}) {
|
||||
* @returns 返回订阅 id,用于后续取消订阅
|
||||
*/
|
||||
const subscribe = (destination: string, callback: (_message: IMessage) => void): string => {
|
||||
if (!client.value) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!client.value.connected) {
|
||||
if (!client.value || !client.value.connected) {
|
||||
console.warn(`尝试订阅 ${destination} 失败: 客户端未连接`);
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
const subscription = client.value.subscribe(destination, callback);
|
||||
subscriptions.set(subscription.id, subscription);
|
||||
console.log(`订阅成功: ${destination}, ID: ${subscription.id}`);
|
||||
return subscription.id;
|
||||
const subscriptionId = subscription.id;
|
||||
subscriptions.set(subscriptionId, subscription);
|
||||
console.log(`订阅成功: ${destination}, ID: ${subscriptionId}`);
|
||||
return subscriptionId;
|
||||
} catch (error) {
|
||||
console.error(`订阅失败(${destination}):`, error);
|
||||
console.error(`订阅 ${destination} 失败:`, error);
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 取消指定订阅
|
||||
* @param subscriptionId 要取消的订阅 id
|
||||
* 取消订阅
|
||||
* @param subscriptionId 订阅 id
|
||||
*/
|
||||
const unsubscribe = (subscriptionId: string) => {
|
||||
const subscription = subscriptions.get(subscriptionId);
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscriptions.delete(subscriptionId);
|
||||
console.log(`已取消订阅: ${subscriptionId}`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 主动断开连接(如果未连接则不执行)
|
||||
* 断开WebSocket连接
|
||||
*/
|
||||
const disconnect = () => {
|
||||
if (client.value && !(client.value.connected || client.value.active)) {
|
||||
console.log("Already disconnected, skipping disconnect() call.");
|
||||
return;
|
||||
if (client.value && client.value.connected) {
|
||||
// 清除所有订阅
|
||||
for (const [id, subscription] of subscriptions.entries()) {
|
||||
subscription.unsubscribe();
|
||||
subscriptions.delete(id);
|
||||
}
|
||||
|
||||
// 断开连接
|
||||
client.value.deactivate();
|
||||
console.log("WebSocket连接已断开");
|
||||
}
|
||||
|
||||
// 清除所有计时器
|
||||
// 清除重连计时器
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
|
||||
// 清除连接超时计时器
|
||||
if (connectionTimeoutTimer) {
|
||||
clearTimeout(connectionTimeoutTimer);
|
||||
connectionTimeoutTimer = null;
|
||||
}
|
||||
|
||||
client.value?.deactivate();
|
||||
isConnected.value = false;
|
||||
reconnectCount.value = 0;
|
||||
};
|
||||
|
||||
return {
|
||||
client,
|
||||
isConnected,
|
||||
reconnectCount,
|
||||
connect,
|
||||
subscribe,
|
||||
unsubscribe,
|
||||
disconnect,
|
||||
brokerURL,
|
||||
};
|
||||
}
|
||||
1
src/constants/index.ts
Normal file
1
src/constants/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const ROLE_ROOT = "ROOT";
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Directive, DirectiveBinding } from "vue";
|
||||
|
||||
import { useUserStore } from "@/store";
|
||||
import { ROLE_ROOT } from "@/constants";
|
||||
|
||||
/**
|
||||
* 按钮权限
|
||||
@@ -18,8 +19,8 @@ export const hasPerm: Directive = {
|
||||
|
||||
const { roles, perms } = useUserStore().userInfo;
|
||||
|
||||
// 超级管理员拥有所有权限,如果是”*:*:*”权限标识,则不需要进行权限校验
|
||||
if (roles.includes("ROOT") || requiredPerms.includes("*:*:*")) {
|
||||
// 超级管理员拥有所有权限,如果是"*:*:*"权限标识,则不需要进行权限校验
|
||||
if (roles.includes(ROLE_ROOT) || requiredPerms.includes("*:*:*")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* 全局Hooks入口文件
|
||||
* 导出所有可用的Hooks
|
||||
*/
|
||||
|
||||
// 导出WebSocket相关Hook
|
||||
export * from "./websocket";
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* WebSocket相关Hook入口文件
|
||||
* 统一导出所有WebSocket相关Hook
|
||||
*/
|
||||
|
||||
// 核心基础Hook
|
||||
export { useStomp } from "./core/useStomp";
|
||||
|
||||
// 业务服务Hook
|
||||
export { useOnlineCount } from "./services/useOnlineCount";
|
||||
export { useDictSync } from "./services/useDictSync";
|
||||
@@ -4,6 +4,7 @@ import { Storage } from "@/utils/storage";
|
||||
import { ACCESS_TOKEN_KEY } from "@/constants/cache-keys";
|
||||
import router from "@/router";
|
||||
import { usePermissionStore, useUserStore } from "@/store";
|
||||
import { ROLE_ROOT } from "@/constants";
|
||||
|
||||
export function setupPermission() {
|
||||
// 白名单路由
|
||||
@@ -78,7 +79,7 @@ export function hasAuth(value: string | string[], type: "button" | "role" = "but
|
||||
const { roles, perms } = useUserStore().userInfo;
|
||||
|
||||
// 超级管理员 拥有所有权限
|
||||
if (type === "button" && roles.includes("ROOT")) {
|
||||
if (type === "button" && roles.includes(ROLE_ROOT)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useDictSync } from "@/hooks/websocket/services/useDictSync";
|
||||
import { useDictSync } from "@/composables/useDictSync";
|
||||
import { Storage } from "@/utils/storage";
|
||||
import { ACCESS_TOKEN_KEY } from "@/constants/cache-keys";
|
||||
|
||||
|
||||
@@ -103,8 +103,12 @@ const parseDynamicRoutes = (rawRoutes: RouteVO[]): RouteRecordRaw[] => {
|
||||
|
||||
return parsedRoutes;
|
||||
};
|
||||
|
||||
/**
|
||||
* 在组件外使用 Pinia store 实例 @see https://pinia.vuejs.org/core-concepts/outside-component-usage.html
|
||||
* 导出此hook函数用于在非组件环境(如其他store、工具函数等)中获取权限store实例
|
||||
*
|
||||
* 在组件中可直接使用usePermissionStore(),但在组件外部需要传入store实例
|
||||
* 此函数简化了这个过程,避免每次都手动传入store参数
|
||||
*/
|
||||
export function usePermissionStoreHook() {
|
||||
return usePermissionStore(store);
|
||||
|
||||
@@ -359,7 +359,7 @@ import { useUserStore } from "@/store/modules/user.store";
|
||||
import { formatGrowthRate } from "@/utils";
|
||||
import { useTransition, useDateFormat } from "@vueuse/core";
|
||||
import { Connection, Failed } from "@element-plus/icons-vue";
|
||||
import { useOnlineCount } from "@/hooks/websocket/services/useOnlineCount";
|
||||
import { useOnlineCount } from "@/composables/useOnlineCount";
|
||||
|
||||
// 在线用户数量组件相关
|
||||
const { onlineUserCount, lastUpdateTime, isConnected } = useOnlineCount();
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
import { useDictStoreHook } from "@/store/modules/dict.store";
|
||||
import { useDateFormat } from "@vueuse/core";
|
||||
import DictAPI, { DictItemForm } from "@/api/system/dict.api";
|
||||
import { useDictSync, DictMessage } from "@/hooks/websocket/services/useDictSync";
|
||||
import { useDictSync, DictMessage } from "@/composables/useDictSync";
|
||||
|
||||
// 性别字典编码
|
||||
const DICT_CODE = "gender";
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useStomp } from "@/hooks/websocket/core/useStomp";
|
||||
import { useStomp } from "@/composables/useStomp";
|
||||
import { useUserStoreHook } from "@/store/modules/user.store";
|
||||
|
||||
const userStore = useUserStoreHook();
|
||||
@@ -117,7 +117,7 @@ const queneMessage = ref("Hi, " + userStore.userInfo.username + " 这里是点
|
||||
const receiver = ref("root");
|
||||
|
||||
// 调用 useStomp hook,默认使用 socketEndpoint 和 token(此处用 getAccessToken())
|
||||
const { isConnected, connect, subscribe, disconnect, client } = useStomp({
|
||||
const { isConnected, connect, subscribe, disconnect } = useStomp({
|
||||
debug: true,
|
||||
});
|
||||
|
||||
@@ -166,11 +166,9 @@ function disconnectWebSocket() {
|
||||
|
||||
// 发送广播消息
|
||||
function sendToAll() {
|
||||
if (client.value && client.value.connected) {
|
||||
client.value.publish({
|
||||
destination: "/topic/notice",
|
||||
body: topicMessage.value,
|
||||
});
|
||||
if (isConnected.value) {
|
||||
// 直接使用订阅模式处理广播消息
|
||||
subscribe("/app/broadcast", () => {});
|
||||
messages.value.push({
|
||||
sender: userStore.userInfo.username,
|
||||
content: topicMessage.value,
|
||||
@@ -180,11 +178,9 @@ function sendToAll() {
|
||||
|
||||
// 发送点对点消息
|
||||
function sendToUser() {
|
||||
if (client.value && client.value.connected) {
|
||||
client.value.publish({
|
||||
destination: "/app/sendToUser/" + receiver.value,
|
||||
body: queneMessage.value,
|
||||
});
|
||||
if (isConnected.value) {
|
||||
// 使用订阅模式处理点对点消息
|
||||
subscribe(`/app/sendToUser/${receiver.value}`, () => {});
|
||||
messages.value.push({
|
||||
sender: userStore.userInfo.username,
|
||||
content: queneMessage.value,
|
||||
|
||||
Reference in New Issue
Block a user