修改用户授权调用位置和逻辑
This commit is contained in:
81
fetchUserInfo_analysis.md
Normal file
81
fetchUserInfo_analysis.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# fetchUserInfo 调用分析
|
||||
|
||||
## 调用位置汇总
|
||||
|
||||
### ✅ 合理的调用
|
||||
|
||||
1. **src/services/loginService.ts** (第160行)
|
||||
- 登录成功后调用,确保用户信息同步到 store
|
||||
- ✅ 合理
|
||||
|
||||
2. **src/main_pages/index.tsx** (第63行)
|
||||
- 微信授权成功后调用
|
||||
- ✅ 合理(主入口,需要确保用户信息加载)
|
||||
|
||||
3. **src/game_pages/list/index.tsx** (第228行)
|
||||
- 在 useEffect 中,等待 waitForAuthInit 后调用
|
||||
- ✅ 合理
|
||||
|
||||
4. **src/game_pages/detail/index.tsx** (第55行)
|
||||
- 在 useEffect 中,等待 waitForAuthInit 后调用
|
||||
- ✅ 合理
|
||||
|
||||
5. **src/game_pages/sharePoster/index.tsx** (第47行)
|
||||
- 在 handleGenPoster 中,等待 waitForAuthInit 后调用
|
||||
- ✅ 合理(需要用户信息生成海报)
|
||||
|
||||
6. **src/components/NTRPTestEntryCard/index.tsx** (第35行)
|
||||
- 在 useEffect 中,等待 waitForAuthInit 后调用
|
||||
- ✅ 合理
|
||||
|
||||
7. **src/utils/authInit.ts** (第29、39行)
|
||||
- 在静默登录成功后调用
|
||||
- ✅ 合理(核心授权逻辑)
|
||||
|
||||
8. **src/home_pages/index.tsx** (第20行)
|
||||
- 在静默登录成功后调用
|
||||
- ✅ 合理
|
||||
|
||||
### ⚠️ 可能重复的调用
|
||||
|
||||
1. **src/main_pages/components/ListPageContent.tsx** (第204行)
|
||||
- 在 useEffect 中调用,等待 waitForAuthInit
|
||||
- ⚠️ **问题**:这是 `main_pages/index.tsx` 的子组件
|
||||
- `main_pages/index.tsx` 已经在授权成功后调用了 `fetchUserInfo`
|
||||
- **建议**:移除这里的调用,因为父组件已经调用了
|
||||
|
||||
2. **src/other_pages/ntrp-evaluate/index.tsx - Intro组件** (第159、180行)
|
||||
- 第159行:在 useEffect 中检查 userInfo 为空时调用
|
||||
- 第180行:在 getLastResult 中检查 userInfo 为空时调用
|
||||
- ⚠️ **问题**:两个地方都可能调用,有重复风险
|
||||
- **建议**:移除第159行的调用,只在 getLastResult 中调用(因为已经等待了 waitForAuthInit)
|
||||
|
||||
3. **src/other_pages/ntrp-evaluate/index.tsx - Result组件** (第463、475行)
|
||||
- 第463行:在 useEffect 中检查 userInfo 为空时调用
|
||||
- 第475行:在 init 中检查 userInfo 为空时调用
|
||||
- ⚠️ **问题**:两个地方都可能调用,有重复风险
|
||||
- **建议**:移除第463行的调用,只在 init 中调用(因为已经等待了 waitForAuthInit)
|
||||
|
||||
## 优化建议
|
||||
|
||||
### 1. 移除重复调用
|
||||
- `main_pages/components/ListPageContent.tsx` - 移除 fetchUserInfo 调用(父组件已调用)
|
||||
- `ntrp-evaluate/index.tsx` - Intro 组件:移除第一个 useEffect 中的调用
|
||||
- `ntrp-evaluate/index.tsx` - Result 组件:移除第一个 useEffect 中的调用
|
||||
|
||||
### 2. 调用原则
|
||||
- ✅ 主入口页面(main_pages/index.tsx)应该在授权成功后调用
|
||||
- ✅ 子组件不应该重复调用,应该依赖父组件或 store 中的数据
|
||||
- ✅ 独立页面(如 game_pages/*)可以调用,但应该等待 waitForAuthInit
|
||||
- ✅ 工具函数(authInit.ts)中的调用是必要的
|
||||
|
||||
## 总结
|
||||
|
||||
**当前问题**:
|
||||
1. `main_pages/components/ListPageContent.tsx` 与父组件重复调用
|
||||
2. `ntrp-evaluate/index.tsx` 中 Intro 和 Result 组件都有重复调用
|
||||
|
||||
**建议修复**:
|
||||
- 移除子组件中的重复调用
|
||||
- 统一在等待 waitForAuthInit 后的逻辑中调用
|
||||
|
||||
10
src/app.ts
10
src/app.ts
@@ -5,8 +5,7 @@ import "./app.scss";
|
||||
import "./scss/qweather-icons/qweather-icons.css";
|
||||
import { useGlobalStore } from "./store/global";
|
||||
import { removeStorage } from "./store/storage";
|
||||
import { sceneRedirectLogic } from './utils/helper'
|
||||
import { silentLogin } from "./services/loginService";
|
||||
import { sceneRedirectLogic } from './utils/helper';
|
||||
|
||||
interface AppProps {
|
||||
children: ReactNode;
|
||||
@@ -25,9 +24,9 @@ class App extends Component<AppProps> {
|
||||
// 这里可以自定义弹窗(或直接默认同意)
|
||||
resolve({ event: 'agree' }); // 同意隐私协议
|
||||
});
|
||||
|
||||
// 移除这里的静默登录调用,避免重复调用
|
||||
// 静默登录在 home_pages/index.tsx 中统一执行
|
||||
|
||||
// 微信授权逻辑已转移到 main_pages/index.tsx 中
|
||||
// 不再在 app.ts 中执行静默登录
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -40,6 +39,7 @@ class App extends Component<AppProps> {
|
||||
|
||||
componentDidShow(options) {
|
||||
sceneRedirectLogic(options.query, options.path);
|
||||
// 微信授权逻辑已转移到 main_pages/index.tsx 中
|
||||
}
|
||||
|
||||
componentDidHide() { }
|
||||
|
||||
@@ -4,6 +4,7 @@ import Taro from "@tarojs/taro";
|
||||
import { useUserInfo, useUserActions } from "@/store/userStore";
|
||||
// import { getCurrentFullPath } from "@/utils";
|
||||
import evaluateService, { StageType } from "@/services/evaluateService";
|
||||
import { waitForAuthInit } from "@/utils/authInit";
|
||||
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
|
||||
import ArrowRight from "@/static/ntrp/ntrp_arrow_right_color.svg";
|
||||
import {
|
||||
@@ -26,12 +27,18 @@ function NTRPTestEntryCard(props: {
|
||||
console.log(userInfo);
|
||||
|
||||
useEffect(() => {
|
||||
if (!userInfo.id) {
|
||||
fetchUserInfo();
|
||||
}
|
||||
evaluateService.getLastResult().then((res) => {
|
||||
const init = async () => {
|
||||
// 先等待静默登录完成
|
||||
await waitForAuthInit();
|
||||
// 然后再获取用户信息
|
||||
if (!userInfo.id) {
|
||||
await fetchUserInfo();
|
||||
}
|
||||
// 获取测试结果
|
||||
const res = await evaluateService.getLastResult();
|
||||
setTestFlag(res.code === 0 && res.data.has_ntrp_level);
|
||||
});
|
||||
};
|
||||
init();
|
||||
}, [userInfo.id]);
|
||||
|
||||
const handleTest = useCallback(
|
||||
|
||||
@@ -7,6 +7,7 @@ import OrderService from "@/services/orderService";
|
||||
import { EvaluateCallback, EvaluateScene } from "@/store/evaluateStore";
|
||||
import { MATCH_STATUS, IsSubstituteSupported } from "@/services/detailService";
|
||||
import { GameManagePopup, NTRPEvaluatePopup } from "@/components";
|
||||
import { useUserInfo } from "@/store/userStore";
|
||||
import img from "@/config/images";
|
||||
import RMB_ICON from "@/static/detail/rmb.svg";
|
||||
import { toast, navto } from "@/utils/helper";
|
||||
@@ -76,6 +77,7 @@ export default function StickyButton(props) {
|
||||
currentUserInfo,
|
||||
} = props;
|
||||
const [commentCount, setCommentCount] = useState(0);
|
||||
const userInfo = useUserInfo();
|
||||
const ntrpRef = useRef<{
|
||||
show: (evaluateCallback: EvaluateCallback) => void;
|
||||
}>({ show: () => {} });
|
||||
@@ -93,6 +95,36 @@ export default function StickyButton(props) {
|
||||
|
||||
const { ntrp_level } = currentUserInfo || {};
|
||||
|
||||
// 检查手机号绑定的包装函数
|
||||
const checkPhoneAndExecute = (action: () => void) => {
|
||||
return () => {
|
||||
if (!userInfo?.phone) {
|
||||
Taro.showModal({
|
||||
title: '提示',
|
||||
content: '该功能需要绑定手机号',
|
||||
confirmText: '去绑定',
|
||||
cancelText: '取消',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
const currentPath = Taro.getCurrentInstance().router?.path || '';
|
||||
const currentParams = Taro.getCurrentInstance().router?.params || {};
|
||||
const queryString = Object.keys(currentParams)
|
||||
.map(key => `${key}=${currentParams[key]}`)
|
||||
.join('&');
|
||||
const fullPath = queryString ? `${currentPath}?${queryString}` : currentPath;
|
||||
|
||||
Taro.navigateTo({
|
||||
url: `/login_pages/index/index?redirect=${encodeURIComponent(fullPath)}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
action();
|
||||
};
|
||||
};
|
||||
|
||||
const matchNtrpReq = matchNtrpRequestment(
|
||||
ntrp_level,
|
||||
skill_level_min,
|
||||
@@ -224,14 +256,14 @@ export default function StickyButton(props) {
|
||||
<Text className={styles.btnText}>继续支付</Text>
|
||||
</>
|
||||
),
|
||||
action: async () => {
|
||||
action: checkPhoneAndExecute(async () => {
|
||||
const res = await OrderService.getUnpaidOrder(id);
|
||||
if (res.code === 0) {
|
||||
navto(
|
||||
`/order_pages/orderDetail/index?id=${res.data.order_info.order_id}`
|
||||
);
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
} else if (!matchNtrpReq) {
|
||||
return {
|
||||
@@ -255,7 +287,7 @@ export default function StickyButton(props) {
|
||||
<Text className={styles.btnText}>我要候补</Text>
|
||||
</>
|
||||
),
|
||||
action: handleJoinGame,
|
||||
action: checkPhoneAndExecute(handleJoinGame),
|
||||
};
|
||||
} else if (can_join) {
|
||||
return {
|
||||
@@ -268,7 +300,7 @@ export default function StickyButton(props) {
|
||||
</>
|
||||
);
|
||||
},
|
||||
action: handleJoinGame,
|
||||
action: checkPhoneAndExecute(handleJoinGame),
|
||||
};
|
||||
} else if (can_assess) {
|
||||
return {
|
||||
@@ -279,7 +311,7 @@ export default function StickyButton(props) {
|
||||
<Text className={styles.btnText}>立即加入</Text>
|
||||
</>
|
||||
),
|
||||
action: handleSelfEvaluate,
|
||||
action: checkPhoneAndExecute(handleSelfEvaluate),
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as LoginService from "@/services/loginService";
|
||||
import { getCurrentLocation } from "@/utils/locationUtils";
|
||||
import { useUserInfo, useUserActions } from "@/store/userStore";
|
||||
import { useGlobalState } from "@/store/global";
|
||||
import { waitForAuthInit } from "@/utils/authInit";
|
||||
import { requireLoginWithPhone } from "@/utils/helper";
|
||||
import GameTags from "./components/GameTags";
|
||||
import Carousel from "./components/Carousel";
|
||||
@@ -46,8 +47,14 @@ function Index() {
|
||||
const commentRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
updateLocation();
|
||||
fetchUserInfo();
|
||||
const init = async () => {
|
||||
updateLocation();
|
||||
// 先等待静默登录完成
|
||||
await waitForAuthInit();
|
||||
// 然后再获取用户信息
|
||||
await fetchUserInfo();
|
||||
};
|
||||
init();
|
||||
}, []);
|
||||
|
||||
useDidShow(() => {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { updateUserLocation } from "@/services/userService";
|
||||
import { useUserActions } from "@/store/userStore";
|
||||
import { useDictionaryStore } from "@/store/dictionaryStore";
|
||||
import { saveImage } from "@/utils";
|
||||
import { waitForAuthInit } from "@/utils/authInit";
|
||||
|
||||
const ListPage = () => {
|
||||
// 从 store 获取数据和方法
|
||||
@@ -220,11 +221,14 @@ const ListPage = () => {
|
||||
getCities();
|
||||
getCityQrCode();
|
||||
|
||||
// 2. 延迟执行:获取用户信息(不阻塞渲染)
|
||||
requestAnimationFrame(() => {
|
||||
fetchUserInfo().catch((error) => {
|
||||
// 2. 延迟执行:等待静默登录完成后获取用户信息
|
||||
requestAnimationFrame(async () => {
|
||||
try {
|
||||
await waitForAuthInit();
|
||||
await fetchUserInfo();
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 3. 延迟执行:获取位置信息(可能较慢,不阻塞首屏)
|
||||
|
||||
@@ -14,6 +14,7 @@ import WechatTimeline from "@/static/detail/wechat_timeline.svg";
|
||||
import { useUserActions } from "@/store/userStore";
|
||||
import { DayOfWeekMap } from "../detail/config";
|
||||
import { genNTRPRequirementText } from "@/utils/helper";
|
||||
import { waitForAuthInit } from "@/utils/authInit";
|
||||
import styles from "./index.module.scss";
|
||||
|
||||
function SharePoster(props) {
|
||||
@@ -41,6 +42,8 @@ function SharePoster(props) {
|
||||
image_list,
|
||||
title,
|
||||
} = detail || {};
|
||||
// 先等待静默登录完成
|
||||
await waitForAuthInit();
|
||||
const userInfo = await fetchUserInfo();
|
||||
const { avatar_url, nickname } = userInfo;
|
||||
const startTime = dayjs(start_time);
|
||||
|
||||
@@ -9,7 +9,6 @@ import { View, Image, Text, ScrollView } from "@tarojs/components";
|
||||
import ListContainer from "@/container/listContainer";
|
||||
import DistanceQuickFilter from "@/components/DistanceQuickFilter";
|
||||
import { updateUserLocation } from "@/services/userService";
|
||||
import { useUserActions } from "@/store/userStore";
|
||||
import { useDictionaryStore } from "@/store/dictionaryStore";
|
||||
import { saveImage, navigateTo } from "@/utils";
|
||||
|
||||
@@ -35,7 +34,6 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
onFilterPopupVisibleChange,
|
||||
}) => {
|
||||
const store = useListStore() || {};
|
||||
const { fetchUserInfo } = useUserActions();
|
||||
const { statusNavbarHeightInfo, getCurrentLocationInfo } =
|
||||
useGlobalState() || {};
|
||||
const { totalHeight = 98 } = statusNavbarHeightInfo || {};
|
||||
@@ -196,12 +194,8 @@ const ListPageContent: React.FC<ListPageContentProps> = ({
|
||||
getCities();
|
||||
getCityQrCode();
|
||||
|
||||
// 2. 延迟执行:获取用户信息(不阻塞渲染)
|
||||
requestAnimationFrame(() => {
|
||||
fetchUserInfo().catch((error) => {
|
||||
console.error('获取用户信息失败:', error);
|
||||
});
|
||||
});
|
||||
// 2. 移除 fetchUserInfo 调用,因为父组件 main_pages/index.tsx 已经在授权成功后调用了
|
||||
// 这里直接使用 store 中的用户信息即可
|
||||
|
||||
// 3. 延迟执行:获取位置信息(可能较慢,不阻塞首屏)
|
||||
requestAnimationFrame(() => {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { View } from "@tarojs/components";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { check_login_status, silentLogin } from "@/services/loginService";
|
||||
import { wechat_auth_login, save_login_state } from "@/services/loginService";
|
||||
import { useUserActions } from "@/store/userStore";
|
||||
import tokenManager from "@/utils/tokenManager";
|
||||
import GuideBar from "@/components/GuideBar";
|
||||
import { GeneralNavbar } from "@/components";
|
||||
import HomeNavbar from "@/components/HomeNavbar";
|
||||
@@ -24,41 +25,66 @@ const MainPage: React.FC = () => {
|
||||
const [isShowInputCustomerNavBar, setIsShowInputCustomerNavBar] = useState(false);
|
||||
const [listPageScrollToTopTrigger, setListPageScrollToTopTrigger] = useState(0);
|
||||
const [showGuideBar, setShowGuideBar] = useState(true);
|
||||
const [showAuthError, setShowAuthError] = useState(false);
|
||||
const [authErrorMessage, setAuthErrorMessage] = useState('');
|
||||
|
||||
const { fetchUserInfo } = useUserActions();
|
||||
|
||||
// 初始化:尝试静默登录并获取用户信息
|
||||
// 初始化:自动微信授权并获取用户信息
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
// 先检查是否已登录
|
||||
const login_status = check_login_status();
|
||||
if (login_status) {
|
||||
// 已登录,获取用户信息
|
||||
const hasValidToken = tokenManager.hasValidToken();
|
||||
|
||||
if (!hasValidToken) {
|
||||
try {
|
||||
console.log('开始微信授权...');
|
||||
const loginRes = await wechat_auth_login();
|
||||
|
||||
if (loginRes.success && loginRes.token) {
|
||||
save_login_state(loginRes.token, loginRes.user_info);
|
||||
console.log('微信授权成功');
|
||||
} else {
|
||||
// 显示错误提示
|
||||
setAuthErrorMessage(loginRes.message || '微信授权失败');
|
||||
setShowAuthError(true);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('微信授权异常:', error);
|
||||
setAuthErrorMessage('微信授权失败,请重试');
|
||||
setShowAuthError(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有有效token,获取用户详细信息
|
||||
if (tokenManager.hasValidToken()) {
|
||||
try {
|
||||
await fetchUserInfo();
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
}
|
||||
} else {
|
||||
// 未登录,尝试静默登录
|
||||
try {
|
||||
const loginResult = await silentLogin();
|
||||
if (loginResult.success) {
|
||||
// 静默登录成功,获取用户信息
|
||||
fetchUserInfo().catch((error) => {
|
||||
console.error('获取用户信息失败:', error);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('静默登录失败:', error);
|
||||
// 静默登录失败不影响使用
|
||||
}
|
||||
}
|
||||
};
|
||||
init();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []); // fetchUserInfo 是稳定的函数引用,不需要加入依赖项
|
||||
|
||||
// 显示授权错误提示
|
||||
useEffect(() => {
|
||||
if (showAuthError) {
|
||||
Taro.showModal({
|
||||
title: '授权失败',
|
||||
content: `${authErrorMessage}\n\n请重启小程序后重试`,
|
||||
showCancel: false,
|
||||
confirmText: '我知道了',
|
||||
success: () => {
|
||||
setShowAuthError(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, [showAuthError, authErrorMessage]);
|
||||
|
||||
// 处理标签切换
|
||||
const handleTabChange = useCallback((code: string) => {
|
||||
if (code === currentTab) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useEvaluate, EvaluateScene } from "@/store/evaluateStore";
|
||||
import { useGlobalState } from "@/store/global";
|
||||
import { delay, getCurrentFullPath } from "@/utils";
|
||||
import { formatNtrpDisplay } from "@/utils/helper";
|
||||
import { waitForAuthInit } from "@/utils/authInit";
|
||||
import CloseIcon from "@/static/ntrp/ntrp_close_icon.svg";
|
||||
import DocCopy from "@/static/ntrp/ntrp_doc_copy.svg";
|
||||
import ArrowRight from "@/static/ntrp/ntrp_arrow_right.svg";
|
||||
@@ -151,16 +152,14 @@ function Intro() {
|
||||
const { ntrp_level, create_time, id } = last_test_result || {};
|
||||
const lastTestTime = create_time ? dayjs(create_time).format("YYYY年M月D日") : "";
|
||||
|
||||
// 组件初始化时立即获取用户信息
|
||||
useEffect(() => {
|
||||
// 如果用户信息为空,立即获取
|
||||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||||
fetchUserInfo();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
getLastResult();
|
||||
const init = async () => {
|
||||
// 先等待静默登录完成
|
||||
await waitForAuthInit();
|
||||
// 然后再调用接口
|
||||
await getLastResult();
|
||||
};
|
||||
init();
|
||||
}, []);
|
||||
|
||||
async function getLastResult() {
|
||||
@@ -193,9 +192,8 @@ function Intro() {
|
||||
});
|
||||
}
|
||||
Taro.redirectTo({
|
||||
url: `/other_pages/ntrp-evaluate/index?stage=${type}${
|
||||
type === StageType.RESULT ? `&id=${id}` : ""
|
||||
}`,
|
||||
url: `/other_pages/ntrp-evaluate/index?stage=${type}${type === StageType.RESULT ? `&id=${id}` : ""
|
||||
}`,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -450,20 +448,18 @@ function Result() {
|
||||
[propName: string, prop: number][]
|
||||
>([]);
|
||||
|
||||
// 组件初始化时立即获取用户信息
|
||||
useEffect(() => {
|
||||
// 如果用户信息为空,立即获取
|
||||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||||
fetchUserInfo();
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
getResultById();
|
||||
// 确保用户信息已加载
|
||||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||||
fetchUserInfo();
|
||||
}
|
||||
const init = async () => {
|
||||
// 先等待静默登录完成
|
||||
await waitForAuthInit();
|
||||
// 然后再调用接口
|
||||
await getResultById();
|
||||
// 确保用户信息已加载
|
||||
if (!userInfo || Object.keys(userInfo).length === 0) {
|
||||
await fetchUserInfo();
|
||||
}
|
||||
};
|
||||
init();
|
||||
}, [id]);
|
||||
|
||||
async function getResultById() {
|
||||
@@ -624,9 +620,8 @@ function Result() {
|
||||
}
|
||||
const currentPage = getCurrentFullPath();
|
||||
Taro.redirectTo({
|
||||
url: `/login_pages/index/index${
|
||||
currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : ""
|
||||
}`,
|
||||
url: `/login_pages/index/index${currentPage ? `?redirect=${encodeURIComponent(currentPage)}` : ""
|
||||
}`,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ export interface UserInfoType {
|
||||
}
|
||||
|
||||
// 微信授权登录
|
||||
// phone_code: 可选参数,如果提供则绑定手机号,否则只进行微信授权
|
||||
export const wechat_auth_login = async (
|
||||
phone_code?: string,
|
||||
): Promise<LoginResponse> => {
|
||||
@@ -94,11 +95,18 @@ export const wechat_auth_login = async (
|
||||
};
|
||||
}
|
||||
|
||||
// 使用 httpService 调用微信授权接口,传递手机号code
|
||||
const auth_response = await httpService.post("user/wx_auth", {
|
||||
// 构建请求参数
|
||||
const requestData: any = {
|
||||
code: login_result.code,
|
||||
phone_code: phone_code, // 传递手机号加密code
|
||||
});
|
||||
};
|
||||
|
||||
// 只有在提供 phone_code 时才添加到请求参数中
|
||||
if (phone_code) {
|
||||
requestData.phone_code = phone_code;
|
||||
}
|
||||
|
||||
// 使用 httpService 调用微信授权接口
|
||||
const auth_response = await httpService.post("user/wx_auth", requestData);
|
||||
|
||||
if (auth_response.code === 0) {
|
||||
return {
|
||||
|
||||
105
src/utils/authInit.ts
Normal file
105
src/utils/authInit.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { check_login_status, get_user_token, silentLogin } from "@/services/loginService";
|
||||
import { useUser } from "@/store/userStore";
|
||||
import tokenManager from "@/utils/tokenManager";
|
||||
|
||||
// 防止重复调用静默登录
|
||||
let isInitializingAuth = false;
|
||||
let authInitPromise: Promise<void> | null = null;
|
||||
|
||||
// 初始化用户授权的核心逻辑
|
||||
const initUserAuthCore = async (): Promise<void> => {
|
||||
// 如果正在初始化,直接返回现有的 Promise
|
||||
if (isInitializingAuth && authInitPromise) {
|
||||
return authInitPromise;
|
||||
}
|
||||
|
||||
// 如果已经登录且有用户信息,跳过
|
||||
const login_status = check_login_status();
|
||||
const { user, fetchUserInfo } = useUser.getState();
|
||||
if (login_status && user && Object.keys(user).length > 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
isInitializingAuth = true;
|
||||
authInitPromise = (async () => {
|
||||
try {
|
||||
if (login_status) {
|
||||
// 已登录,获取用户信息
|
||||
try {
|
||||
await fetchUserInfo();
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
}
|
||||
} else {
|
||||
// 未登录,尝试静默登录
|
||||
try {
|
||||
const loginResult = await silentLogin();
|
||||
if (loginResult.success) {
|
||||
// 静默登录成功,获取用户信息
|
||||
await fetchUserInfo();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('静默登录失败:', error);
|
||||
// 静默登录失败不影响使用
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化用户授权失败:', error);
|
||||
} finally {
|
||||
isInitializingAuth = false;
|
||||
authInitPromise = null;
|
||||
}
|
||||
})();
|
||||
|
||||
return authInitPromise;
|
||||
};
|
||||
|
||||
// 导出等待静默登录完成的函数,供页面组件使用
|
||||
export const waitForAuthInit = async (): Promise<void> => {
|
||||
// 检查是否已经有有效的 token(最优先检查)
|
||||
if (tokenManager.hasValidToken() || get_user_token()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// 如果正在初始化,等待完成
|
||||
if (authInitPromise) {
|
||||
await authInitPromise;
|
||||
// 等待完成后再次检查 token
|
||||
if (tokenManager.hasValidToken() || get_user_token()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否已经登录且有用户信息
|
||||
const login_status = check_login_status();
|
||||
const { user } = useUser.getState();
|
||||
if (login_status && user && Object.keys(user).length > 0) {
|
||||
// 即使有登录状态,也确保 token 存在
|
||||
if (tokenManager.hasValidToken() || get_user_token()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
// 触发初始化
|
||||
const promise = initUserAuthCore();
|
||||
await promise;
|
||||
|
||||
// 等待 token 真正存在(最多等待 2 秒)
|
||||
let retryCount = 0;
|
||||
const maxRetries = 20; // 20 * 100ms = 2秒
|
||||
while (retryCount < maxRetries && !tokenManager.hasValidToken() && !get_user_token()) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
retryCount++;
|
||||
}
|
||||
|
||||
// 如果还是没有 token,记录警告但继续执行
|
||||
if (!tokenManager.hasValidToken() && !get_user_token()) {
|
||||
console.warn('等待静默登录完成,但未获取到 token');
|
||||
}
|
||||
};
|
||||
|
||||
// 导出初始化函数供 app.ts 使用
|
||||
export const initUserAuth = () => {
|
||||
return initUserAuthCore();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user