Jelajahi Sumber

feat: 加载用户信息

BaiLuoYan 1 bulan lalu
induk
melakukan
3f0e8ac6ac

+ 3 - 3
src/config/request/authHeaderInterceptor.ts

@@ -29,7 +29,7 @@ class TokenRefresh {
                             const accessToken = info.accessToken!;
                             setToken({
                                 accessToken: accessToken,
-                                expires: info.expires,
+                                accessExpires: info.accessExpires,
                                 refreshToken: info.refreshToken,
                             });
                             config.headers = config.headers ?? {};
@@ -66,11 +66,11 @@ export const authHeaderInterceptor: IRequestInterceptorAxios = (config: RequestC
     if (config.requireToken !== true) return config;
 
     const data = getToken();
-    const expires = (data?.expires ?? 0) - currentUnixTimestamp() > 0;
+    const expires = (data?.accessExpires ?? 0) - currentUnixTimestamp() > 0;
     if (data?.accessToken && expires) {
         config.headers['Authorization'] = formatToken(data.accessToken);
         return config;
     } else {
-        return TokenRefresh.beforeRequestRefreshTokenFirst(config, data?.refreshToken ?? 'none'); // 如果 refreshToken 为空,接口会返回 401 错误,跳转到登录页
+        return TokenRefresh.beforeRequestRefreshTokenFirst(config, data?.refreshToken || 'none'); // 如果 refreshToken 为空,接口会返回 401 错误,跳转到登录页
     }
 };

+ 28 - 0
src/models/userConfigModel.ts

@@ -0,0 +1,28 @@
+import { useState, useCallback } from 'react';
+
+import { createModel } from '../utils/model/createModel';
+
+interface UserConfigState {
+    userConfig: API.UserInfo | null;
+}
+
+interface UserConfigModel extends UserConfigState {
+    setUserConfig: (data: API.UserInfo | null) => void;
+}
+
+const useUserConfigModel = (): UserConfigModel => {
+    const [state, setState] = useState<UserConfigState>({
+        userConfig: null,
+    });
+
+    const setUserConfig = useCallback((data: API.UserInfo | null) => {
+        setState({ userConfig: data });
+    }, []);
+
+    return {
+        ...state,
+        setUserConfig,
+    };
+};
+
+export const userConfigModel = createModel(useUserConfigModel, 'userConfig');

+ 0 - 19
src/pages/pricing/components/OrderSummary/useService.ts

@@ -1,14 +1,8 @@
 import { useMemo } from 'react';
 
-import { createLocalTools } from '@/utils/localUtils';
-import { userKey } from '@/utils/authUtils';
-
 import type { Plan } from '../../useService';
 
-const ls = createLocalTools();
-
 export interface UseServiceReturn {
-    userAccount: string;
     currentSubscription: string;
     orderTotal: string;
 }
@@ -18,18 +12,6 @@ export interface UseServiceParams {
 }
 
 export function useService({ selectedPlan }: UseServiceParams): UseServiceReturn {
-    const userInfo = ls.getLocal<API.UserInfo>(userKey);
-
-    const userAccount = useMemo(() => {
-        if (!userInfo) return '';
-        if (userInfo.email) return userInfo.email;
-        if (userInfo.phone) return userInfo.phone;
-        if (userInfo.username) return userInfo.username;
-        if (userInfo.userId) return userInfo.userId;
-        if (userInfo.deviceId) return userInfo.deviceId;
-        return '';
-    }, [userInfo]);
-
     const currentSubscription = useMemo(() => {
         if (!selectedPlan) {
             return '';
@@ -45,7 +27,6 @@ export function useService({ selectedPlan }: UseServiceParams): UseServiceReturn
     }, [selectedPlan]);
 
     return {
-        userAccount,
         currentSubscription,
         orderTotal,
     };

+ 7 - 15
src/pages/pricing/components/UserInfo/useService.ts

@@ -1,9 +1,6 @@
 import { useMemo } from 'react';
 
-import { createLocalTools } from '@/utils/localUtils';
-import { userKey } from '@/utils/authUtils';
-
-const ls = createLocalTools();
+import { userConfigModel } from '@/models/userConfigModel';
 
 export interface UseServiceReturn {
     userAccount: string;
@@ -11,23 +8,18 @@ export interface UseServiceReturn {
 }
 
 export function useService(): UseServiceReturn {
-    const userInfo = ls.getLocal<API.UserInfo>(userKey);
+    const { userConfig } = userConfigModel.useModel();
 
     const userAccount = useMemo(() => {
-        if (!userInfo) return '';
-        if (userInfo.email) return userInfo.email;
-        if (userInfo.phone) return userInfo.phone;
-        if (userInfo.username) return userInfo.username;
-        if (userInfo.userId) return userInfo.userId;
-        if (userInfo.deviceId) return userInfo.deviceId;
-        return '';
-    }, [userInfo]);
+        if (!userConfig) return '';
+        return userConfig.account?.username || '';
+    }, [userConfig]);
 
     const planExpireDate = useMemo(() => {
-        if (!userInfo) return 0;
+        if (!userConfig) return 0;
         // TODO: 调用 api 获取用户当前套餐信息,返回套餐到期时间
         return 0;
-    }, []);
+    }, [userConfig]);
 
     return {
         userAccount,

+ 22 - 1
src/pages/pricing/useService.ts

@@ -1,6 +1,10 @@
-import { useMemo } from 'react';
+import { useEffect, useMemo } from 'react';
 
 import { PlanTagType, PayMethodType } from '@/defines';
+import { userConfigModel } from '@/models/userConfigModel';
+import { fetchGetUserConfig } from '@/services/config';
+import { getToken, setToken } from '@/utils/authUtils';
+import { currentUnixTimestamp } from '@/utils/timeUtils';
 
 export interface Plan {
     id: number;
@@ -18,6 +22,23 @@ export interface UseServiceReturn {
 }
 
 export function useService(): UseServiceReturn {
+    const { setUserConfig } = userConfigModel.useModel();
+
+    useEffect(() => {
+        const userinfo = getToken();
+        const expired = (userinfo?.accessExpires ?? 0) - currentUnixTimestamp() <= 0;
+        if (expired) return;
+        if (userinfo?.account?.username) return;
+        fetchGetUserConfig({})
+            .then((res) => {
+                const data = res?.data;
+                if (!data) return;
+                setToken(data);
+                setUserConfig(data);
+            })
+            .catch(() => {});
+    }, [setUserConfig]);
+
     const plans = useMemo<Plan[]>(
         () => [
             {

+ 8 - 0
src/services/config/index.ts

@@ -0,0 +1,8 @@
+import { request } from '@/utils/request';
+
+export async function fetchGetUserConfig(_: API.Empty, options?: { [key: string]: any }) {
+    return request<API.Result<API.UserInfo>>('/app/getUserConfig', {
+        method: 'POST',
+        ...(options || {}),
+    });
+}

+ 0 - 0
src/services/config/typings.d.ts


+ 1 - 1
src/services/login/index.ts

@@ -1,7 +1,7 @@
 import { request } from '@/utils/request';
 
 export async function fetchLogin(body: API.LoginParams, options?: { [key: string]: any }) {
-    return request<API.LoginResult>('/user/login', {
+    return request<API.LoginResult>('/user/owLogin', {
         method: 'POST',
         data: body,
         ...(options || {}),

+ 48 - 20
src/services/login/typings.d.ts

@@ -1,34 +1,62 @@
 declare namespace API {
     type UserInfo = {
-        /** token */
         accessToken?: string;
-        /** 用于调用刷新accessToken的接口时所需的token */
         refreshToken?: string;
-        /** `accessToken`的过期时间(unix时间戳) */
-        expires?: number;
-        /** 用户ID */
-        userId?: string;
-        /** 设备ID */
-        deviceId?: string;
-        /** 用户名 */
+        accessExpires?: number;
+        country?: string;
+        countryName?: string;
+        userIp?: string;
+        createTime?: number;
+        geographyEea?: boolean;
+        memberLevel?: number;
+        userLevel?: number;
+        expireTime?: number;
+        remainTime?: number;
+        isExpired?: boolean;
+        isTestUser?: boolean;
+        isSubscribeUser?: boolean;
+        account?: Account;
+        planInfo?: PlanInfo;
+    };
+
+    type Account = {
         username?: string;
-        /** 昵称 */
-        nickname?: string;
-        /** 头像 */
-        avatar?: string;
-        /** 邮箱 */
-        email?: string;
-        /** 手机号 */
         phone?: string;
-        /** 推荐码 */
-        refer?: string;
+        email?: string;
+        wechat?: string;
+        qq?: string;
+        google?: string;
+        apple?: string;
+    };
+
+    type PlanInfo = {
+        channelItemId?: string;
+        title?: string;
+        subTitle?: string;
+        introduce?: string;
+        orgPrice?: number;
+        price?: number;
+        tag?: string;
+        tagType?: number;
+        currency?: number;
+        recommend?: boolean;
+        isDefault?: boolean;
+        sort?: number;
+        deviceLimit?: number;
+        isSubscribe?: boolean;
+        subscribeType?: number;
+        subscribePeriodValue?: number;
+        payoutType?: string;
+        payoutData?: string;
+        ServicePlanId?: number;
+        ServiceChannelPlanId?: number;
     };
 
     type LoginParams = {
         username: string;
         password: string;
-        captchaId: string;
-        captchaCode: string;
+        captchaId?: string; // 新的登录接口不用验证码
+        captchaCode?: string; // 新的登录接口不用验证码
     };
 
     type LoginResult = Result<UserInfo>;

+ 11 - 44
src/utils/authUtils.ts

@@ -23,66 +23,33 @@ export function getToken(): API.UserInfo {
  * 将除了 accessToken 之外的其他信息放在 key 值为 user-info 的 localStorage 里
  */
 export function setToken(data: API.UserInfo) {
-    const { accessToken = '', expires = 0, refreshToken = '' } = data;
-    const cookieString = JSON.stringify({ accessToken, expires, refreshToken });
+    const { accessToken = '', accessExpires = 0, refreshToken = '' } = data;
+    const cookieString = JSON.stringify({ accessToken, accessExpires, refreshToken });
 
-    if (expires > 0) {
+    if (accessExpires > 0) {
         Cookies.set(tokenKey, cookieString, {
-            expires: (expires * 1000 - currentJsTimestamp()) / 86400000,
+            expires: (accessExpires * 1000 - currentJsTimestamp()) / 86400000,
         });
     } else {
         Cookies.set(tokenKey, cookieString);
     }
 
-    function setUserKey({
-        userId,
-        deviceId,
-        username,
-        nickname,
-        avatar,
-        email,
-        phone,
-        refer,
-    }: API.UserInfo) {
+    function setUserKey(data: API.UserInfo) {
+        const { accessToken: _, accessExpires: __, refreshToken: ___, ...rest } = data;
         ls.setLocal(userKey, {
             refreshToken,
-            expires,
-            userId,
-            deviceId,
-            username,
-            nickname,
-            avatar,
-            email,
-            phone,
-            refer,
+            accessExpires,
+            ...rest,
         });
     }
 
-    if (data.userId || data.deviceId) {
+    if (data.account?.username) {
         // 登录时,后端接口会返回用户信息,直接设置到 localStorage 中
-        setUserKey({
-            userId: data.userId || '',
-            deviceId: data.deviceId || '',
-            username: data.username || '',
-            nickname: data.nickname || '',
-            avatar: data.avatar || '',
-            email: data.email || '',
-            phone: data.phone || '',
-            refer: data.refer || '',
-        });
+        setUserKey(data);
     } else {
         // 刷新 token 时,后端接口不会返回用户信息,需要从 localStorage 中获取用户信息
         const d = ls.getLocal<API.UserInfo>(userKey);
-        setUserKey({
-            userId: d?.userId || '',
-            deviceId: d?.deviceId || '',
-            username: d?.username || '',
-            nickname: d?.nickname || '',
-            avatar: d?.avatar || '',
-            email: d?.email || '',
-            phone: d?.phone || '',
-            refer: d?.refer || '',
-        });
+        setUserKey({ ...d });
     }
 }
 

+ 2 - 0
types/typings.d.ts

@@ -41,4 +41,6 @@ declare namespace API {
     interface ReqDelete<T extends number | string = number> {
         ids: T[];
     }
+
+    type Empty = Record<string, never>;
 }