refactor: restructure core architecture and responsive system
This commit implements a major architectural refactor to improve modularity, type safety, and maintainability across the codebase.
Key changes include:
- **Responsive System Refactor**: Migrated from a monolithic `useResponsive` hook to a set of specialized, granular hooks (`useBreakpoint`, `useOrientation`, `usePlatform`, etc.) located in `src/presentation/hooks/responsive`. This reduces unnecessary re-renders and improves developer experience.
- **Core Service Restructuring**: Introduced a new directory structure for services, including dedicated folders for `datasources`, `mappers`, and domain-specific types (`message`, `post`).
- **Data Layer Improvements**:
- Centralized JSON parsing logic in `src/database/core/jsonUtils.ts`.
- Cleaned up repository implementations by removing redundant local utility functions.
- Refactored `MessageMapper` to use the new centralized JSON utility.
- **Type System Cleanup**:
- Decomposed the large `src/types/dto.ts` into a modular `src/types/dto/` directory.
- Simplified `src/types/index.ts` and introduced backward-compatible aliases for core entities.
- **Utility Consolidation**:
- Created a centralized `src/utils/formatTime.ts` to replace fragmented date formatting logic across various screens and components.
- Removed deprecated responsive utility files in favor of the new hook-based system.
- **Service Logic Refinement**: Refactored `ApiClient` and `WebSocketService` to use a centralized `showVerificationModal` service, removing duplicated state management for verification prompts.
This commit is contained in:
@@ -10,6 +10,7 @@ import Constants from 'expo-constants';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
import { eventBus } from '@/core/events/EventBus';
|
||||
import { showVerificationModal } from './verification';
|
||||
|
||||
// 生产地址 https://withyou.littlelan.cn
|
||||
const getBaseUrl = () => {
|
||||
@@ -73,8 +74,7 @@ interface JwtPayload {
|
||||
// API 客户端类
|
||||
class ApiClient {
|
||||
private baseUrl: string;
|
||||
private verificationModalShown = false;
|
||||
private refreshLock: Promise<boolean> | null = null;
|
||||
private refreshLock: Promise<boolean> | null = null;
|
||||
private isAuthFailed = false; // 全局认证失败标志,防止无限重试
|
||||
|
||||
constructor(baseUrl: string) {
|
||||
@@ -82,12 +82,7 @@ class ApiClient {
|
||||
}
|
||||
|
||||
private handleVerificationRequired() {
|
||||
if (this.verificationModalShown) return;
|
||||
this.verificationModalShown = true;
|
||||
eventBus.emit({ type: 'SHOW_VERIFICATION_MODAL' });
|
||||
setTimeout(() => {
|
||||
this.verificationModalShown = false;
|
||||
}, 3000);
|
||||
showVerificationModal();
|
||||
}
|
||||
|
||||
private navigateToLogin() {
|
||||
|
||||
98
src/services/core/datasources/ApiDataSource.ts
Normal file
98
src/services/core/datasources/ApiDataSource.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* API 数据源实现
|
||||
* 封装所有 API 调用,统一错误处理和请求拦截
|
||||
*/
|
||||
|
||||
import { api, ApiResponse, ApiError } from '@/services/core';
|
||||
import { IApiDataSource, DataSourceError } from './interfaces';
|
||||
|
||||
export class ApiDataSource implements IApiDataSource {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor(baseUrl?: string) {
|
||||
this.baseUrl = baseUrl || '';
|
||||
}
|
||||
|
||||
private buildUrl(url: string): string {
|
||||
if (url.startsWith('http')) {
|
||||
return url;
|
||||
}
|
||||
return `${this.baseUrl}${url}`;
|
||||
}
|
||||
|
||||
private handleError(error: unknown, operation: string): never {
|
||||
if (error instanceof ApiError) {
|
||||
throw new DataSourceError(
|
||||
error.message,
|
||||
String(error.code),
|
||||
'ApiDataSource',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
const message = error instanceof Error ? error.message : 'Unknown error';
|
||||
throw new DataSourceError(
|
||||
`API ${operation} failed: ${message}`,
|
||||
'API_ERROR',
|
||||
'ApiDataSource',
|
||||
error instanceof Error ? error : undefined
|
||||
);
|
||||
}
|
||||
|
||||
async get<T>(url: string, params?: any): Promise<T> {
|
||||
try {
|
||||
const fullUrl = this.buildUrl(url);
|
||||
const response = await api.get<T>(fullUrl, params);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.handleError(error, 'GET');
|
||||
}
|
||||
}
|
||||
|
||||
async post<T>(url: string, data?: any): Promise<T> {
|
||||
try {
|
||||
const fullUrl = this.buildUrl(url);
|
||||
const response = await api.post<T>(fullUrl, data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.handleError(error, 'POST');
|
||||
}
|
||||
}
|
||||
|
||||
async put<T>(url: string, data?: any): Promise<T> {
|
||||
try {
|
||||
const fullUrl = this.buildUrl(url);
|
||||
const response = await api.put<T>(fullUrl, data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.handleError(error, 'PUT');
|
||||
}
|
||||
}
|
||||
|
||||
async delete<T>(url: string, data?: any): Promise<T> {
|
||||
try {
|
||||
const fullUrl = this.buildUrl(url);
|
||||
const response = await api.delete<T>(fullUrl, data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.handleError(error, 'DELETE');
|
||||
}
|
||||
}
|
||||
|
||||
async upload<T>(
|
||||
url: string,
|
||||
file: { uri: string; name: string; type: string },
|
||||
additionalData?: Record<string, string>
|
||||
): Promise<T> {
|
||||
try {
|
||||
const fullUrl = this.buildUrl(url);
|
||||
const response = await api.upload<T>(fullUrl, file, additionalData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.handleError(error, 'UPLOAD');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例实例
|
||||
export const apiDataSource = new ApiDataSource();
|
||||
199
src/services/core/datasources/CacheDataSource.ts
Normal file
199
src/services/core/datasources/CacheDataSource.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* 缓存数据源实现
|
||||
* 基于内存和 AsyncStorage 的混合缓存实现
|
||||
*/
|
||||
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { ICacheDataSource, DataSourceError } from './interfaces';
|
||||
|
||||
interface CacheEntry<T> {
|
||||
value: T;
|
||||
expiry: number | null; // null 表示永不过期
|
||||
}
|
||||
|
||||
export class CacheDataSource implements ICacheDataSource {
|
||||
private memoryCache: Map<string, CacheEntry<any>> = new Map();
|
||||
private maxSize: number;
|
||||
private defaultTtl: number; // 默认过期时间(毫秒)
|
||||
private persistPrefix: string;
|
||||
|
||||
constructor(config?: {
|
||||
maxSize?: number;
|
||||
defaultTtl?: number; // 默认5分钟
|
||||
persistPrefix?: string;
|
||||
}) {
|
||||
this.maxSize = config?.maxSize || 100;
|
||||
this.defaultTtl = config?.defaultTtl || 5 * 60 * 1000;
|
||||
this.persistPrefix = config?.persistPrefix || 'cache_';
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 key 是否过期
|
||||
*/
|
||||
private isExpired(entry: CacheEntry<any>): boolean {
|
||||
if (entry.expiry === null) return false;
|
||||
return Date.now() > entry.expiry;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期缓存
|
||||
*/
|
||||
private cleanup(): void {
|
||||
const now = Date.now();
|
||||
for (const [key, entry] of this.memoryCache.entries()) {
|
||||
if (entry.expiry !== null && now > entry.expiry) {
|
||||
this.memoryCache.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果仍然超过最大大小,删除最旧的条目
|
||||
while (this.memoryCache.size > this.maxSize) {
|
||||
const firstKey = this.memoryCache.keys().next().value;
|
||||
if (firstKey !== undefined) {
|
||||
this.memoryCache.delete(firstKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成持久化存储 key
|
||||
*/
|
||||
private getPersistKey(key: string): string {
|
||||
return `${this.persistPrefix}${key}`;
|
||||
}
|
||||
|
||||
// ==================== ICacheDataSource 实现 ====================
|
||||
|
||||
async get<T>(key: string): Promise<T | null> {
|
||||
try {
|
||||
// 先检查内存缓存
|
||||
const memoryEntry = this.memoryCache.get(key);
|
||||
if (memoryEntry) {
|
||||
if (!this.isExpired(memoryEntry)) {
|
||||
return memoryEntry.value as T;
|
||||
}
|
||||
// 过期了,从内存中删除
|
||||
this.memoryCache.delete(key);
|
||||
}
|
||||
|
||||
// 尝试从持久化存储读取
|
||||
const persistKey = this.getPersistKey(key);
|
||||
const stored = await AsyncStorage.getItem(persistKey);
|
||||
if (stored) {
|
||||
const entry: CacheEntry<T> = JSON.parse(stored);
|
||||
if (!this.isExpired(entry)) {
|
||||
// 重新加载到内存缓存
|
||||
this.memoryCache.set(key, entry);
|
||||
this.cleanup();
|
||||
return entry.value;
|
||||
}
|
||||
// 过期了,删除
|
||||
await AsyncStorage.removeItem(persistKey);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.warn(`[CacheDataSource] Failed to get ${key}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async set<T>(key: string, value: T, ttl?: number): Promise<void> {
|
||||
try {
|
||||
const expiry = ttl === undefined
|
||||
? (this.defaultTtl > 0 ? Date.now() + this.defaultTtl : null)
|
||||
: (ttl > 0 ? Date.now() + ttl : null);
|
||||
|
||||
const entry: CacheEntry<T> = { value, expiry };
|
||||
|
||||
// 存入内存
|
||||
this.memoryCache.set(key, entry);
|
||||
this.cleanup();
|
||||
|
||||
// 持久化存储(重要数据)
|
||||
if (ttl === undefined || ttl > 0) {
|
||||
const persistKey = this.getPersistKey(key);
|
||||
await AsyncStorage.setItem(persistKey, JSON.stringify(entry));
|
||||
}
|
||||
} catch (error) {
|
||||
throw new DataSourceError(
|
||||
`Failed to set cache ${key}`,
|
||||
'CACHE_SET_ERROR',
|
||||
'CacheDataSource',
|
||||
error instanceof Error ? error : undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async delete(key: string): Promise<void> {
|
||||
try {
|
||||
// 从内存删除
|
||||
this.memoryCache.delete(key);
|
||||
|
||||
// 从持久化存储删除
|
||||
const persistKey = this.getPersistKey(key);
|
||||
await AsyncStorage.removeItem(persistKey);
|
||||
} catch (error) {
|
||||
throw new DataSourceError(
|
||||
`Failed to delete cache ${key}`,
|
||||
'CACHE_DELETE_ERROR',
|
||||
'CacheDataSource',
|
||||
error instanceof Error ? error : undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async clear(): Promise<void> {
|
||||
try {
|
||||
// 清空内存
|
||||
this.memoryCache.clear();
|
||||
|
||||
// 清空持久化存储中的所有缓存项
|
||||
const keys = await AsyncStorage.getAllKeys();
|
||||
const cacheKeys = keys.filter(k => k.startsWith(this.persistPrefix));
|
||||
if (cacheKeys.length > 0) {
|
||||
await AsyncStorage.multiRemove(cacheKeys);
|
||||
}
|
||||
} catch (error) {
|
||||
throw new DataSourceError(
|
||||
'Failed to clear cache',
|
||||
'CACHE_CLEAR_ERROR',
|
||||
'CacheDataSource',
|
||||
error instanceof Error ? error : undefined
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async has(key: string): Promise<boolean> {
|
||||
try {
|
||||
// 检查内存
|
||||
const memoryEntry = this.memoryCache.get(key);
|
||||
if (memoryEntry && !this.isExpired(memoryEntry)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查持久化存储
|
||||
const persistKey = this.getPersistKey(key);
|
||||
const stored = await AsyncStorage.getItem(persistKey);
|
||||
if (stored) {
|
||||
const entry: CacheEntry<any> = JSON.parse(stored);
|
||||
return !this.isExpired(entry);
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async getMultiple<T>(keys: string[]): Promise<(T | null)[]> {
|
||||
return Promise.all(keys.map(key => this.get<T>(key)));
|
||||
}
|
||||
|
||||
async setMultiple<T>(entries: { key: string; value: T; ttl?: number }[]): Promise<void> {
|
||||
await Promise.all(entries.map(entry => this.set(entry.key, entry.value, entry.ttl)));
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例实例
|
||||
export const cacheDataSource = new CacheDataSource();
|
||||
184
src/services/core/datasources/WSClient.ts
Normal file
184
src/services/core/datasources/WSClient.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* WSClient - WebSocket连接管理
|
||||
* 只负责WebSocket连接管理,提供事件驱动架构
|
||||
*/
|
||||
|
||||
import {
|
||||
wsService,
|
||||
WSChatMessage,
|
||||
WSGroupChatMessage,
|
||||
WSReadMessage,
|
||||
WSGroupReadMessage,
|
||||
WSRecallMessage,
|
||||
WSGroupRecallMessage,
|
||||
WSGroupTypingMessage,
|
||||
WSGroupNoticeMessage,
|
||||
WSMessageType,
|
||||
} from '@/services/core';
|
||||
|
||||
// 事件处理器类型
|
||||
type EventHandler<T> = (data: T) => void;
|
||||
|
||||
// WS事件类型
|
||||
export interface WSEvents {
|
||||
'chat': WSChatMessage;
|
||||
'group_message': WSGroupChatMessage;
|
||||
'read': WSReadMessage;
|
||||
'group_read': WSGroupReadMessage;
|
||||
'recall': WSRecallMessage;
|
||||
'group_recall': WSGroupRecallMessage;
|
||||
'group_typing': WSGroupTypingMessage;
|
||||
'group_notice': WSGroupNoticeMessage;
|
||||
'connected': void;
|
||||
'disconnected': void;
|
||||
'error': Error;
|
||||
}
|
||||
|
||||
export type WSEventType = keyof WSEvents;
|
||||
|
||||
class WSClient {
|
||||
private handlers: Map<WSEventType, Set<EventHandler<any>>> = new Map();
|
||||
private unsubscribeFns: Array<() => void> = [];
|
||||
private isInitialized = false;
|
||||
|
||||
/**
|
||||
* 初始化WebSocket监听
|
||||
*/
|
||||
initialize(): void {
|
||||
if (this.isInitialized) return;
|
||||
|
||||
// 监听私聊消息
|
||||
const unsubChat = wsService.on('chat', (message) => {
|
||||
this.emit('chat', message);
|
||||
});
|
||||
|
||||
// 监听群聊消息
|
||||
const unsubGroupMessage = wsService.on('group_message', (message) => {
|
||||
this.emit('group_message', message);
|
||||
});
|
||||
|
||||
// 监听私聊已读回执
|
||||
const unsubRead = wsService.on('read', (message) => {
|
||||
this.emit('read', message);
|
||||
});
|
||||
|
||||
// 监听群聊已读回执
|
||||
const unsubGroupRead = wsService.on('group_read', (message) => {
|
||||
this.emit('group_read', message);
|
||||
});
|
||||
|
||||
// 监听私聊消息撤回
|
||||
const unsubRecall = wsService.on('recall', (message) => {
|
||||
this.emit('recall', message);
|
||||
});
|
||||
|
||||
// 监听群聊消息撤回
|
||||
const unsubGroupRecall = wsService.on('group_recall', (message) => {
|
||||
this.emit('group_recall', message);
|
||||
});
|
||||
|
||||
// 监听群聊输入状态
|
||||
const unsubGroupTyping = wsService.on('group_typing', (message) => {
|
||||
this.emit('group_typing', message);
|
||||
});
|
||||
|
||||
// 监听群通知
|
||||
const unsubGroupNotice = wsService.on('group_notice', (message) => {
|
||||
this.emit('group_notice', message);
|
||||
});
|
||||
|
||||
// 监听连接状态
|
||||
const unsubConnect = wsService.onConnect(() => {
|
||||
this.emit('connected', undefined);
|
||||
});
|
||||
|
||||
const unsubDisconnect = wsService.onDisconnect(() => {
|
||||
this.emit('disconnected', undefined);
|
||||
});
|
||||
|
||||
this.unsubscribeFns = [
|
||||
unsubChat,
|
||||
unsubGroupMessage,
|
||||
unsubRead,
|
||||
unsubGroupRead,
|
||||
unsubRecall,
|
||||
unsubGroupRecall,
|
||||
unsubGroupTyping,
|
||||
unsubGroupNotice,
|
||||
unsubConnect,
|
||||
unsubDisconnect,
|
||||
];
|
||||
|
||||
this.isInitialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁WebSocket监听
|
||||
*/
|
||||
destroy(): void {
|
||||
this.unsubscribeFns.forEach((fn) => fn());
|
||||
this.unsubscribeFns = [];
|
||||
this.handlers.clear();
|
||||
this.isInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅事件
|
||||
*/
|
||||
on<T extends WSEventType>(
|
||||
event: T,
|
||||
handler: EventHandler<WSEvents[T]>
|
||||
): () => void {
|
||||
if (!this.handlers.has(event)) {
|
||||
this.handlers.set(event, new Set());
|
||||
}
|
||||
this.handlers.get(event)!.add(handler);
|
||||
|
||||
return () => {
|
||||
this.handlers.get(event)?.delete(handler);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发事件
|
||||
*/
|
||||
private emit<T extends WSEventType>(
|
||||
event: T,
|
||||
data: WSEvents[T]
|
||||
): void {
|
||||
const handlers = this.handlers.get(event);
|
||||
if (handlers) {
|
||||
handlers.forEach((handler) => {
|
||||
try {
|
||||
handler(data);
|
||||
} catch (error) {
|
||||
console.error(`[WSClient] 事件处理器执行失败: ${event}`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查连接状态
|
||||
*/
|
||||
isConnected(): boolean {
|
||||
return wsService.isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动WebSocket连接
|
||||
*/
|
||||
async connect(): Promise<boolean> {
|
||||
return wsService.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开WebSocket连接
|
||||
*/
|
||||
disconnect(): void {
|
||||
wsService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
export const wsClient = new WSClient();
|
||||
export default wsClient;
|
||||
9
src/services/core/datasources/index.ts
Normal file
9
src/services/core/datasources/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 数据源导出
|
||||
* 统一导出所有数据源实现
|
||||
*/
|
||||
|
||||
export * from './interfaces';
|
||||
export * from './ApiDataSource';
|
||||
export { LocalDataSource, localDataSource } from '@/database';
|
||||
export * from './CacheDataSource';
|
||||
68
src/services/core/datasources/interfaces.ts
Normal file
68
src/services/core/datasources/interfaces.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 数据源接口定义
|
||||
* 定义所有数据源的标准接口,便于替换和测试
|
||||
*/
|
||||
|
||||
// API 数据源接口
|
||||
export interface IApiDataSource {
|
||||
get<T>(url: string, params?: any): Promise<T>;
|
||||
post<T>(url: string, data?: any): Promise<T>;
|
||||
put<T>(url: string, data?: any): Promise<T>;
|
||||
delete<T>(url: string, data?: any): Promise<T>;
|
||||
upload<T>(url: string, file: { uri: string; name: string; type: string }, additionalData?: Record<string, string>): Promise<T>;
|
||||
}
|
||||
|
||||
// 本地数据源接口 (SQLite)
|
||||
export interface ILocalDataSource {
|
||||
query<T>(sql: string, params?: any[]): Promise<T[]>;
|
||||
getFirst<T>(sql: string, params?: any[]): Promise<T | null>;
|
||||
execute(sql: string, params?: any[]): Promise<void>;
|
||||
run(sql: string, params?: any[]): Promise<{ lastInsertRowId: number; changes: number }>;
|
||||
transaction(operations: () => Promise<void>): Promise<void>;
|
||||
batch(operations: (db: ILocalDataSource) => Promise<void>): Promise<void>;
|
||||
enqueueWrite<T>(operation: () => Promise<T>): Promise<T>;
|
||||
initialize(userId?: string): Promise<void>;
|
||||
switchDatabase(userId?: string | null): Promise<void>;
|
||||
closeDatabase(): Promise<void>;
|
||||
}
|
||||
|
||||
// 缓存数据源接口
|
||||
export interface ICacheDataSource {
|
||||
get<T>(key: string): Promise<T | null>;
|
||||
set<T>(key: string, value: T, ttl?: number): Promise<void>;
|
||||
delete(key: string): Promise<void>;
|
||||
clear(): Promise<void>;
|
||||
has(key: string): Promise<boolean>;
|
||||
getMultiple<T>(keys: string[]): Promise<(T | null)[]>;
|
||||
setMultiple<T>(entries: { key: string; value: T; ttl?: number }[]): Promise<void>;
|
||||
}
|
||||
|
||||
// 数据源错误类型
|
||||
export class DataSourceError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public code: string,
|
||||
public source: string,
|
||||
public originalError?: Error
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'DataSourceError';
|
||||
}
|
||||
}
|
||||
|
||||
// 数据源配置
|
||||
export interface DataSourceConfig {
|
||||
api?: {
|
||||
baseUrl: string;
|
||||
timeout?: number;
|
||||
retryCount?: number;
|
||||
};
|
||||
local?: {
|
||||
dbName: string;
|
||||
version: number;
|
||||
};
|
||||
cache?: {
|
||||
maxSize: number;
|
||||
defaultTtl: number;
|
||||
};
|
||||
}
|
||||
12
src/services/core/verification.ts
Normal file
12
src/services/core/verification.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { eventBus } from '@/core/events/EventBus';
|
||||
|
||||
let verificationModalShown = false;
|
||||
|
||||
export function showVerificationModal(): void {
|
||||
if (verificationModalShown) return;
|
||||
verificationModalShown = true;
|
||||
eventBus.emit({ type: 'SHOW_VERIFICATION_MODAL' });
|
||||
setTimeout(() => {
|
||||
verificationModalShown = false;
|
||||
}, 3000);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { api, WS_URL } from './api';
|
||||
import { eventBus } from '@/core/events/EventBus';
|
||||
import { MessageCategory, SystemMessageType, SystemMessageExtraData, MessageSegment } from '@/types/dto';
|
||||
import { systemNotificationService } from '../notification/systemNotificationService';
|
||||
import { showVerificationModal } from './verification';
|
||||
|
||||
export type WSMessageType =
|
||||
| 'chat'
|
||||
@@ -1147,15 +1148,8 @@ class WebSocketService {
|
||||
this.lastActivityAt = Date.now();
|
||||
}
|
||||
|
||||
private verificationModalShown = false;
|
||||
|
||||
private handleVerificationRequired(): void {
|
||||
if (this.verificationModalShown) return;
|
||||
this.verificationModalShown = true;
|
||||
eventBus.emit({ type: 'SHOW_VERIFICATION_MODAL' });
|
||||
setTimeout(() => {
|
||||
this.verificationModalShown = false;
|
||||
}, 3000);
|
||||
showVerificationModal();
|
||||
}
|
||||
|
||||
private startHeartbeat(): void {
|
||||
|
||||
Reference in New Issue
Block a user