This commit is contained in:
oneao committed 2025-06-18 16:30:01 +08:00
1 parent bcc4722efc
commit f48536774f
403 files changed
+34776

No files matched your search

@@ -0,0 +1,12 @@
import { ref } from "vue";
import { AreaResult } from "@/service/area";
import { PropertyResult } from "@/service/peoperty";
const areaOptions = ref<AreaResult[]>([]);
const propertyOptions = ref<PropertyResult[]>([]);
export const useCommonOptions = () => {
return {
areaOptions,
propertyOptions
};
};
@@ -0,0 +1,61 @@
import { ref } from "vue";
import { defineStore } from "pinia";
import { useRouter } from "vue-router";
export interface ErrorInfo {
responseData: Response;
originUrl?: string;
extraData?: any;
}
type Response<T = unknown> = {
code: number;
message: string;
data: T;
};
enum ResponseStatus {
UNAUTHORIZED = 401,
NOT_FOUND = 404
}
export const useErrorStore = defineStore("error", () => {
const error = ref<ErrorInfo | null>(null);
const router = useRouter();
// 设置错误信息,传入 Response 对象
function setError(response: Response, extraData?: any) {
clearError();
// 记录错误信息
error.value = {
responseData: response,
originUrl: router.currentRoute.value.fullPath,
extraData: extraData
};
// 根据不同的 code 进行页面跳转
switch (response.code) {
case ResponseStatus.UNAUTHORIZED:
if (router.currentRoute.value.path !== "/login") {
router.push("/login");
}
break;
case ResponseStatus.NOT_FOUND:
router.push("/404");
break;
default:
router.push("/404");
break;
}
}
function clearError() {
error.value = null;
}
return {
error,
setError,
clearError
};
});
@@ -0,0 +1,34 @@
import { defineStore } from "pinia";
import { ref, computed } from "vue";
import { GetChatsResult } from "@/service/message";
export const useImMessageStore = defineStore("im-message", () => {
const activeChatCompany = ref<GetChatsResult>({ companyId: "", companyName: "" });
const allNoReadNumber = ref<number>(0);
const setActiveChatCompany = (val: GetChatsResult) => {
activeChatCompany.value = val;
};
const resetActiveChatCompany = () => {
activeChatCompany.value = {
companyId: "",
companyName: ""
};
};
const isActiveChatCompany = computed<boolean>(() => {
return !!activeChatCompany.value?.companyId?.trim();
});
const setAllNoReadNumber = (data: number) => {
allNoReadNumber.value = data;
};
return {
activeChatCompany,
setActiveChatCompany,
resetActiveChatCompany,
isActiveChatCompany,
allNoReadNumber,
setAllNoReadNumber
};
});
@@ -0,0 +1,9 @@
import type { App } from "vue";
import { createPinia } from "pinia";
import { createPersistedState } from "pinia-plugin-persistedstate"; // 数据持久化
export function setupPinia(app: App) {
const store = createPinia();
store.use(createPersistedState());
app.use(store);
}
@@ -0,0 +1,18 @@
import { defineStore } from "pinia";
import { useRoute } from "vue-router";
import { RouteLocationRaw, useRouter } from "vue-router";
export const useRouterStore = defineStore("router", () => {
const route = useRoute();
const router = useRouter();
const getCurrentPath = () => {
return route.path;
};
const toPath = (params: RouteLocationRaw) => {
router.push(params);
};
return {
getCurrentPath,
toPath
};
});
@@ -0,0 +1,14 @@
import { ref } from "vue";
import { defineStore } from "pinia";
export const useSearchCompanyStore = defineStore("search-company", () => {
const selectedAreaValue = ref<string[]>([]);
const selectedIndustryValue = ref<string[]>([]);
const searchNameValue = ref<string>("");
return {
selectedAreaValue,
selectedIndustryValue,
searchNameValue
};
});
@@ -0,0 +1,62 @@
import { defineStore } from "pinia";
import { computed, ref } from "vue";
type IUserInfo = {
id: string;
account?: string;
email?: string;
name?: string;
token?: string;
avatar?: string;
};
const initState = { id: "", account: "", email: "", name: "", token: "" };
export const useUserStore = defineStore(
"user",
() => {
const userInfo = ref<IUserInfo>({ ...initState });
const setUserInfo = (val: IUserInfo) => {
userInfo.value = val;
};
const clearUserInfo = () => {
reset();
};
// 一般没有reset需求,不需要的可以删除
const reset = () => {
userInfo.value = {
id: "",
account: "",
email: "",
name: "",
token: "",
avatar: ""
};
};
// ✅ 如果需要同时验证多个字段
const isLogined = computed(() => {
return !!(
(
userInfo.value.token && // 用户令牌
userInfo.value.id && // 用户ID
// userInfo.value.email && // 邮箱
userInfo.value.account // 账户名
)
// userInfo.value.name // 名称
);
});
return {
userInfo,
setUserInfo,
clearUserInfo,
isLogined,
reset
};
},
{
persist: true
}
);
@@ -0,0 +1,136 @@
// stores/websocket.ts
import { defineStore } from "pinia";
import { ref, onScopeDispose } from "vue";
import { WebSocketType } from "@/types/websocket"; // 确保类型导入路径正确
export const useWebSocketStore = defineStore("websocket", () => {
// 状态定义
const socket = ref<WebSocket | null>(null);
const isConnected = ref(false);
const listeners = ref<Set<(msg: WebSocketType.AcceptMessageType) => void>>(new Set());
// 私有状态
let reconnectAttempts = 0;
let pingInterval: number;
let pongTimeout: number;
const PING_INTERVAL = 5000;
const PONG_TIMEOUT = 10000;
const MAX_RECONNECT_ATTEMPTS = 5;
// 公共方法 ----
const connect = (url: string) => {
if (isConnected.value) {
return;
}
if (socket.value) disconnect();
const newSocket = new WebSocket(url);
newSocket.onopen = () => {
isConnected.value = true;
reconnectAttempts = 0;
startHeartbeat();
};
newSocket.onmessage = (event) => {
try {
const message: WebSocketType.AcceptMessageType = JSON.parse(event.data);
// 处理心跳响应
if (message.type === WebSocketType.AcceptMessageEnums.PONG) {
resetPongTimeout();
return;
}
notifyListeners(message);
} catch (error) {
console.error("消息解析失败:", error);
notifyListeners({
type: WebSocketType.AcceptMessageEnums.ERROR,
data: "消息解析失败"
});
}
};
newSocket.onclose = () => {
handleDisconnect();
scheduleReconnect(url);
};
newSocket.onerror = (error) => {
console.error("WebSocket错误:", error);
};
socket.value = newSocket;
};
const disconnect = () => {
socket.value?.close();
cleanup();
};
const sendMessage = <T = any>(type: WebSocketType.SendMessageEnums, data?: T) => {
if (isConnected.value && socket.value) {
const message: WebSocketType.ImSendMessageType<T> = {
type,
data
};
socket.value.send(JSON.stringify(message));
}
};
const onMessage = (callback: (msg: WebSocketType.AcceptMessageType) => void) => {
listeners.value.add(callback);
return () => listeners.value.delete(callback);
};
// 私有方法 ----
const startHeartbeat = () => {
pingInterval = window.setInterval(() => {
sendPing();
}, PING_INTERVAL);
};
const sendPing = () => {
if (socket.value?.readyState === WebSocket.OPEN) {
sendMessage(WebSocketType.SendMessageEnums.PING);
pongTimeout = window.setTimeout(() => socket.value?.close(), PONG_TIMEOUT);
}
};
const resetPongTimeout = () => {
window.clearTimeout(pongTimeout);
};
const notifyListeners = (message: WebSocketType.AcceptMessageType) => {
listeners.value.forEach((cb) => cb(message));
};
const handleDisconnect = () => {
isConnected.value = false;
cleanup();
};
const scheduleReconnect = (url: string) => {
if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {
const delay = Math.min(3000 * 2 ** reconnectAttempts, 30000);
setTimeout(() => connect(url), delay);
reconnectAttempts++;
}
};
const cleanup = () => {
window.clearInterval(pingInterval);
window.clearTimeout(pongTimeout);
};
// 自动清理
onScopeDispose(() => disconnect());
return {
isConnected,
connect,
disconnect,
sendMessage,
onMessage
};
});