u
This commit is contained in:
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
|
||||
};
|
||||
});
|
||||
Reference in new issue
Block a user