feat(home): integrate PagerView for tab navigation and add verification redirect
Replace custom gesture handling with PagerView component for smoother tab switching on home screen. Add verification required redirects in API and WebSocket services that automatically navigate users to the verification guide when receiving VERIFICATION_REQUIRED error codes. BREAKING CHANGE: API and WS services now require router to be set via setExpoRouter/setRouter for navigation to work properly
This commit is contained in:
@@ -10,6 +10,8 @@ import { CommonActions } from '@react-navigation/native';
|
||||
import Constants from 'expo-constants';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
import { hrefVerificationGuide } from '../navigation/hrefs';
|
||||
|
||||
// 生产地址 https://bbs.littlelan.cn
|
||||
const getBaseUrl = () => {
|
||||
const configuredBaseUrl = Constants.expoConfig?.extra?.apiBaseUrl;
|
||||
@@ -49,11 +51,13 @@ export interface PaginatedData<T> {
|
||||
export class ApiError extends Error {
|
||||
code: number;
|
||||
message: string;
|
||||
errorCode?: string;
|
||||
|
||||
constructor(code: number, message: string) {
|
||||
constructor(code: number, message: string, errorCode?: string) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.errorCode = errorCode;
|
||||
this.name = 'ApiError';
|
||||
}
|
||||
}
|
||||
@@ -71,6 +75,8 @@ interface JwtPayload {
|
||||
class ApiClient {
|
||||
private baseUrl: string;
|
||||
private navigation: any = null;
|
||||
private expoRouter: any = null;
|
||||
private verificationModalShown = false;
|
||||
// 刷新锁:防止并发刷新
|
||||
private refreshLock: Promise<boolean> | null = null;
|
||||
|
||||
@@ -78,6 +84,21 @@ class ApiClient {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
setExpoRouter(router: any) {
|
||||
this.expoRouter = router;
|
||||
}
|
||||
|
||||
private handleVerificationRequired() {
|
||||
if (this.verificationModalShown) return;
|
||||
this.verificationModalShown = true;
|
||||
if (this.expoRouter) {
|
||||
this.expoRouter.push(hrefVerificationGuide());
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.verificationModalShown = false;
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 设置导航对象(用于处理401跳转)
|
||||
setNavigation(navigation: any) {
|
||||
this.navigation = navigation;
|
||||
@@ -267,7 +288,10 @@ class ApiClient {
|
||||
if (parsedBody && typeof parsedBody === 'object' && 'code' in parsedBody) {
|
||||
const data = parsedBody as ApiResponse<T>;
|
||||
if (data.code !== 0) {
|
||||
throw new ApiError(data.code, data.message || '请求失败');
|
||||
if (parsedBody.error_code === 'VERIFICATION_REQUIRED') {
|
||||
this.handleVerificationRequired();
|
||||
}
|
||||
throw new ApiError(data.code, data.message || '请求失败', parsedBody.error_code);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { AppState, AppStateStatus } from 'react-native';
|
||||
|
||||
import { api, WS_URL } from './api';
|
||||
import { hrefVerificationGuide } from '../navigation/hrefs';
|
||||
import { MessageCategory, SystemMessageType, SystemMessageExtraData, MessageSegment } from '../types/dto';
|
||||
import { systemNotificationService } from './systemNotificationService';
|
||||
|
||||
@@ -407,11 +408,15 @@ class WebSocketService {
|
||||
// 处理错误消息 - emit 到上层处理
|
||||
if (msg.type === 'error') {
|
||||
console.error('WebSocket error:', msg.payload);
|
||||
const errorCode: string = msg.payload?.code || 'unknown';
|
||||
const err: WSErrorMessage = {
|
||||
type: 'error',
|
||||
code: msg.payload?.code || 'unknown',
|
||||
code: errorCode,
|
||||
message: msg.payload?.message || 'Unknown error',
|
||||
};
|
||||
if (errorCode === 'VERIFICATION_REQUIRED') {
|
||||
this.handleVerificationRequired();
|
||||
}
|
||||
this.emit('error', err);
|
||||
return;
|
||||
}
|
||||
@@ -1112,6 +1117,25 @@ class WebSocketService {
|
||||
this.lastActivityAt = Date.now();
|
||||
}
|
||||
|
||||
private verificationModalShown = false;
|
||||
|
||||
private handleVerificationRequired(): void {
|
||||
if (this.verificationModalShown) return;
|
||||
this.verificationModalShown = true;
|
||||
if (this.routerRef) {
|
||||
this.routerRef.push(hrefVerificationGuide());
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.verificationModalShown = false;
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
private routerRef: any = null;
|
||||
|
||||
setRouter(router: any): void {
|
||||
this.routerRef = router;
|
||||
}
|
||||
|
||||
private startHeartbeat(): void {
|
||||
this.stopHeartbeat();
|
||||
this.heartbeatTimer = setInterval(() => {
|
||||
|
||||
Reference in New Issue
Block a user