From 6bb78c11cd625e450cb827459a7612a567e9141a Mon Sep 17 00:00:00 2001 From: km2025 Date: Wed, 4 Feb 2026 18:38:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8F=B7=EF=BC=8C=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=95=B0=E6=8D=AE=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E7=AE=80=E5=8C=96=E8=AE=A4=E8=AF=81=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.config.js | 2 +- app/(tabs)/_layout.tsx | 18 +------- app/(tabs)/index.tsx | 1 + app/_layout.tsx | 50 ++++++++++------------ app/auth.tsx | 94 +++++++++++++----------------------------- lib/auth.ts | 3 ++ lib/fetch-logger.ts | 22 ---------- stores/userStore.ts | 71 ++++++++++++++----------------- 8 files changed, 88 insertions(+), 173 deletions(-) diff --git a/app.config.js b/app.config.js index cd08500..cda3d97 100644 --- a/app.config.js +++ b/app.config.js @@ -10,7 +10,7 @@ export const IOS_UNIVERSAL_LINK = 'duooomi.bowong.cn' // 原生版本,原生代码变更时需要更新此版本号 export const VERSION = '1.5.0' // JavaScript版本,JS代码变更时需要更新此版本号 -export const APP_VERSION = 'dev202602041525' +export const APP_VERSION = 'dev202602041658' const ALIPAY_SCHEMA = 'alipay2021006119657394' const ALIPAY_SCHEMA_SANDBOX = 'alipay9021000158673972' diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index bad7817..1047ddf 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -61,10 +61,6 @@ const CustomTabBar = observer(function CustomTabBar(props: any) { const activeRouteName = routes[activeIndex]?.name || 'index' const handleChange = (route: string) => { - // if (!isLogin && route !== 'index') { - // props.navigation.push('auth') - // return - // } props.navigation.navigate(route) } return @@ -74,23 +70,11 @@ export default function Layout() { const router = useRouter() useEffect(() => { const timer = setTimeout(() => { - router.replace('(tabs)/sync') + router.replace('/(tabs)/sync') }, 100) // 小延迟确保导航准备好 return () => clearTimeout(timer) }, [router]) - useEffect(() => { - // 配置WebBrowser - // const setupWebBrowser = async () => { - // try { - // await configureWebBrowser() - // } catch (error) { - // console.warn('Failed to configure WebBrowser:', error) - // } - // } - // setupWebBrowser() - }, []) - return }> } diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 94d8225..f5c6e0a 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -68,6 +68,7 @@ const Index = observer(function Index() { useEffect(() => { console.log('expo env------------', process.env.EXPO_PUBLIC_ENV) + userStore.getUserData() }, []) /** ================= refs(核心) ================= */ diff --git a/app/_layout.tsx b/app/_layout.tsx index 37062bb..0df309c 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,13 +1,13 @@ import '../global.css' import 'react-native-reanimated' -import { DarkTheme, DefaultTheme, ThemeProvider, useIsFocused } from '@react-navigation/native' +import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native' import * as Sentry from '@sentry/react-native' import { useKeepAwake } from 'expo-keep-awake' -import { router, Stack, useNavigationContainerRef, usePathname } from 'expo-router' +import { Stack, useNavigationContainerRef, usePathname } from 'expo-router' import { ShareIntentProvider } from 'expo-share-intent' import { StatusBar } from 'expo-status-bar' -import { useCallback, useEffect } from 'react' +import { useEffect } from 'react' import { GestureHandlerRootView } from 'react-native-gesture-handler' import { KeyboardProvider } from 'react-native-keyboard-controller' import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context' @@ -17,8 +17,6 @@ import { bleManager } from '@/ble/managers/bleManager' import { HotUpdate } from '@/components/hot-update' import { useColorScheme } from '@/hooks/use-color-scheme' import { setupGlobalFetchLogger } from '@/lib/fetch-logger' -import { useUserSession } from '@/stores/userStore' -import { storage } from '@/utils' const isProd = process.env.EXPO_PUBLIC_ENV !== 'development' @@ -40,6 +38,8 @@ export const unstable_settings = { function RootLayout() { const ref = useNavigationContainerRef() + const currentRoute = usePathname() + useEffect(() => { if (!ref?.current) return @@ -92,15 +92,15 @@ function RootLayout() { - - - - - - - - - + + + + + + + + + @@ -110,24 +110,16 @@ function RootLayout() { function Providers({ children }: { children: React.ReactNode }) { const colorScheme = useColorScheme() const currentRoute = usePathname() + // const session = useUserSession() - useUserSession() useKeepAwake() - const isFocused = useIsFocused() - - const loadLogin = useCallback(async () => { - const isLogin = await storage.get('isLogin') - if (!isLogin && currentRoute !== '/auth') { - router.replace('/auth') - } - }, [currentRoute]) - - useEffect(() => { - if (isFocused) { - loadLogin() - } - }, [isFocused, loadLogin]) + // useEffect(() => { + // if (session.isPending) return + // if (!isLoggedIn && !currentRoute.includes('/auth')) { + // router.replace('/auth') + // } + // }, [session.isPending, isLoggedIn, currentRoute]) return ( diff --git a/app/auth.tsx b/app/auth.tsx index 7955413..eada799 100644 --- a/app/auth.tsx +++ b/app/auth.tsx @@ -8,7 +8,7 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-controller' import { APP_VERSION, VERSION } from '@/app.config' import BannerSection from '@/components/BannerSection' -import { getSession, phoneNumber, setAuthToken, signIn } from '@/lib/auth' +import { phoneNumber, setAuthToken, signIn } from '@/lib/auth' import { isValidPhone } from '@/utils' const APP_NAME = '多米' @@ -33,50 +33,19 @@ export default function Auth() { const [currentBranch, setCurrentBranch] = useState('unknown') const countdownTimerRef = useRef | null>(null) - // 获取当前分支信息 useEffect(() => { - const getBranchInfo = async () => { - try { - if (!Updates.isEnabled) { - setCurrentBranch('development') - return - } - - // 方法1: 使用 Updates.manifest (同步) - const manifest = Updates.manifest - - // 方法2: 或者尝试从更新中获取 - let branch = 'production' // 默认值 - - if (manifest?.extra?.eas?.branch) { - branch = manifest.extra.eas.branch - } else if (manifest?.metadata?.branchName) { - branch = manifest.metadata.branchName - } else if (Updates.channel) { - branch = Updates.channel - } - - // 方法3: 尝试获取当前运行的更新信息 - try { - const currentlyRunning = await Updates.fetchUpdateAsync() - if (currentlyRunning.manifest?.extra?.eas?.branch) { - branch = currentlyRunning.manifest.extra.eas.branch - } - } catch (e) { - console.log('Failed to fetch current update:', e) - } - - setCurrentBranch(branch) - console.log('Current branch:', branch) - console.log('Updates.channel:', Updates.channel) - console.log('Manifest:', manifest) - } catch (error) { - console.warn('Failed to get branch info:', error) - setCurrentBranch('unknown') - } + if (!Updates.isEnabled) { + setCurrentBranch('development') + return + } + const manifest = Updates.manifest + if (manifest?.extra?.eas?.branch) { + setCurrentBranch(manifest.extra.eas.branch) + } else if (Updates.channel) { + setCurrentBranch(Updates.channel) + } else { + setCurrentBranch('production') } - - getBranchInfo() }, []) const canSendCode = useMemo(() => { @@ -174,29 +143,24 @@ export default function Auth() { setLoading(true) Toast.showLoading({ title: '正在验证...' }) try { - // 验证验证码,如果后端配置了 signUpOnVerification,新用户会自动注册并创建 session - // disableSession: false 表示验证成功后创建 session(自动登录) - await new Promise((resolve, reject) => { - phoneNumber.verify( - { phoneNumber: phone, code: code, disableSession: false }, - { - onSuccess: async (ctx: any) => { - const authToken = ctx.response.headers.get('set-auth-token') - if (authToken) { - setAuthToken(authToken) - } - await getSession() - Toast.show({ title: '登录成功!' }) - setTimeout(() => { - router.replace('/(tabs)') - }, 500) - }, - onError: (ctx: any) => { - reject(new Error(ctx.error.message)) - }, + const result = await phoneNumber.verify( + { phoneNumber: phone, code: code, disableSession: false }, + { + onSuccess: async (ctx: any) => { + const authToken = ctx.response.headers.get('set-auth-token') + if (authToken) { + setAuthToken(authToken) + } }, - ) - }) + }, + ) + + if (result.error) { + Toast.show({ title: result.error.message || '验证失败' }) + } else { + Toast.show({ title: '登录成功!' }) + router.replace('/(tabs)') + } } catch (error: any) { console.error('登录/注册失败:', error) Toast.show({ title: error.message || '操作失败,请稍后重试' }) diff --git a/lib/auth.ts b/lib/auth.ts index 6f2cd36..846dd2a 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -85,6 +85,9 @@ export const authClient = createAuthClient({ trustedOrigins: ['duooomi://', 'https://api.mixvideo.bowong.cc'], storage, scheme: 'duooomi', + sessionOptions: { + refetchOnWindowFocus: false, + }, fetchOptions: { headers: { 'x-ownerid': OWNER_ID, diff --git a/lib/fetch-logger.ts b/lib/fetch-logger.ts index 2c07544..8b182ba 100644 --- a/lib/fetch-logger.ts +++ b/lib/fetch-logger.ts @@ -1,6 +1,3 @@ -import { storage as storage2 } from '../utils/storage' -import { storage } from './storage.native' - interface FetchLoggerOptions { enableLogging?: boolean logRequest?: boolean @@ -26,26 +23,7 @@ export const createFetchWithLogger = (options: FetchLoggerOptions = {}) => { const method = init?.method || 'GET' try { - const token = await storage.getItem('token') - - if (token) { - init = { - ...init, - headers: { - ...init?.headers, - authorization: `Bearer ${token}`, - }, - } - } - const response = await originalFetch(input, init) - - if (response.status === 401) { - console.warn('🔐 401 未授权,清空登录状态') - // router.replace('/auth') - storage2.set('isLogin', false) - } - return response } catch (error) { const duration = Date.now() - startTime diff --git a/stores/userStore.ts b/stores/userStore.ts index 8c0fd7d..36aaa5c 100644 --- a/stores/userStore.ts +++ b/stores/userStore.ts @@ -1,15 +1,13 @@ import { root } from '@repo/core' import { DeviceController } from '@repo/sdk' import * as Application from 'expo-application' +import { router } from 'expo-router' import { makeAutoObservable, runInAction } from 'mobx' -import { useEffect } from 'react' import { Platform } from 'react-native' -import { signOut as authSignOut, useSession } from '@/lib/auth' +import { getSession, signOut as authSignOut } from '@/lib/auth' import { storage } from '@/utils' -// console.log('useSession---------------', useSession) - interface User { id: string email: string @@ -33,17 +31,17 @@ interface User { interface Session { user?: User session?: { - id: string - userId: string expiresAt: Date + token: string createdAt: Date updatedAt: Date + ipAddress?: string | null + userAgent?: string | null + userId: string + impersonatedBy?: string | null activeOrganizationId?: string | null activeTeamId?: string | null - impersonatedBy?: string | null - ipAddress?: string | null - token?: string | null - userAgent?: string | null + id: string } } @@ -77,18 +75,31 @@ class UserStore { await storage.set('isLogin', !!user) } - // 设置会话信息 - async setSession(session: Session | null) { - runInAction(() => { - this.session = session - this.user = session?.user || null - this.isLogin = !!session?.user + async getUserData() { + const sessionRes = await getSession() - if (session?.user) { - this.bindDevice() - } + // console.log('getUserData sessionRes--------:', JSON.stringify(sessionRes)) + + const data = sessionRes.data + if (!data) { + this.reset() + router.replace('/auth') + return + } + + const { session, user } = data + + // console.log('获取用户信息--------:', JSON.stringify(data)) + + runInAction(() => { + this.session = { session, user } + this.user = user || null + this.isLogin = !!user }) - await storage.set('isLogin', !!session?.user) + + if (user?.id) { + this.bindDevice() + } } // 设置加载状态 @@ -118,18 +129,13 @@ class UserStore { } } - // 从session更新用户状态 - updateFromSession(sessionData: Session | null) { - this.setSession(sessionData) - } - // 重置store状态 reset() { - this.user = null this.session = null this.isLoading = false this.error = null this.scannedQR = null + this.setUser(null) } // ==================== 二维码相关方法 ==================== @@ -180,16 +186,3 @@ class UserStore { // 创建单例实例 export const userStore = new UserStore() - -// 创建一个hook来使用session数据更新store -export const useUserSession = () => { - const session = useSession() - - // 使用useEffect在副作用中更新store状态,避免在render过程中修改 - useEffect(() => { - userStore.setLoading(session.isPending) - userStore.updateFromSession(session.data) - }, [session.isPending, session.data]) - - return session -}