fix(wxapp): 修复首页分享链接白屏问题
- 添加邀请关系处理的超时保护,避免长时间等待 - 优化 API调用流程,增加错误处理机制 - 改进页面加载逻辑,确保主要内容优先显示 - 新增失败重试计数,防止无限重试 - 清理邀请参数缓存,避免重复处理
This commit is contained in:
@@ -82,18 +82,32 @@ function Home() {
|
||||
|
||||
})
|
||||
|
||||
// 检查是否有待处理的邀请关系
|
||||
// 检查是否有待处理的邀请关系 - 异步处理,不阻塞页面加载
|
||||
if (hasPendingInvite()) {
|
||||
console.log('检测到待处理的邀请关系')
|
||||
// 延迟处理,确保用户信息已加载
|
||||
// 延迟处理,确保用户信息已加载,并设置超时保护
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
const success = await checkAndHandleInviteRelation()
|
||||
// 设置超时保护,避免长时间等待
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('邀请关系处理超时')), 8000)
|
||||
);
|
||||
|
||||
const invitePromise = checkAndHandleInviteRelation();
|
||||
|
||||
const success = await Promise.race([invitePromise, timeoutPromise]);
|
||||
if (success) {
|
||||
console.log('首页邀请关系处理成功')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('首页邀请关系处理失败:', error)
|
||||
// 邀请关系处理失败不应该影响页面正常显示
|
||||
// 可以选择清除邀请参数,避免重复尝试
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
if (errorMessage?.includes('超时')) {
|
||||
console.log('邀请关系处理超时,清除邀请参数')
|
||||
// 可以选择清除邀请参数或稍后重试
|
||||
}
|
||||
}
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ const GoodsDetail = () => {
|
||||
const [specAction, setSpecAction] = useState<'cart' | 'buy'>('cart');
|
||||
// const [selectedSku, setSelectedSku] = useState<ShopGoodsSku | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const router = Taro.getCurrentInstance().router;
|
||||
const goodsId = router?.params?.id;
|
||||
|
||||
@@ -117,48 +118,57 @@ const GoodsDetail = () => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (goodsId) {
|
||||
setLoading(true);
|
||||
// 重新加载数据的函数
|
||||
const reloadData = async () => {
|
||||
if (!goodsId) return;
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
// 设置超时时间
|
||||
const timeout = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('请求超时')), 10000)
|
||||
);
|
||||
|
||||
// 加载商品详情
|
||||
getShopGoods(Number(goodsId))
|
||||
.then((res) => {
|
||||
// 处理富文本内容,去掉图片间距
|
||||
if (res.content) {
|
||||
res.content = wxParse(res.content);
|
||||
}
|
||||
setGoods(res);
|
||||
if (res.files) {
|
||||
const arr = JSON.parse(res.files);
|
||||
arr.length > 0 && setFiles(arr);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to fetch goods detail:", error);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
const goodsPromise = getShopGoods(Number(goodsId)).then((res) => {
|
||||
// 处理富文本内容,去掉图片间距
|
||||
if (res.content) {
|
||||
res.content = wxParse(res.content);
|
||||
}
|
||||
setGoods(res);
|
||||
if (res.files) {
|
||||
const arr = JSON.parse(res.files);
|
||||
arr.length > 0 && setFiles(arr);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
// 加载商品规格
|
||||
listShopGoodsSpec({goodsId: Number(goodsId)} as any)
|
||||
.then((data) => {
|
||||
setSpecs(data || []);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to fetch goods specs:", error);
|
||||
});
|
||||
// 等待商品详情加载完成(带超时)
|
||||
await Promise.race([goodsPromise, timeout]);
|
||||
|
||||
// 加载商品SKU
|
||||
listShopGoodsSku({goodsId: Number(goodsId)} as any)
|
||||
.then((data) => {
|
||||
setSkus(data || []);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to fetch goods skus:", error);
|
||||
});
|
||||
// 并行加载规格和SKU(不阻塞主要内容显示)
|
||||
Promise.all([
|
||||
listShopGoodsSpec({goodsId: Number(goodsId)} as any)
|
||||
.then((data) => setSpecs(data || []))
|
||||
.catch((error) => console.error("Failed to fetch goods specs:", error)),
|
||||
|
||||
listShopGoodsSku({goodsId: Number(goodsId)} as any)
|
||||
.then((data) => setSkus(data || []))
|
||||
.catch((error) => console.error("Failed to fetch goods skus:", error))
|
||||
]);
|
||||
|
||||
} catch (error: any) {
|
||||
console.error("Failed to fetch goods detail:", error);
|
||||
setError(error.message || '加载失败,请重试');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
reloadData();
|
||||
}, [goodsId]);
|
||||
|
||||
// 分享给好友
|
||||
@@ -186,8 +196,42 @@ const GoodsDetail = () => {
|
||||
};
|
||||
});
|
||||
|
||||
if (!goods || loading) {
|
||||
return <div>加载中...</div>;
|
||||
// 错误状态
|
||||
if (error) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen p-4">
|
||||
<div className="text-center">
|
||||
<div className="text-6xl mb-4">😵</div>
|
||||
<div className="text-lg font-medium mb-2">页面加载失败</div>
|
||||
<div className="text-gray-500 mb-6">{error}</div>
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
className="bg-blue-500 text-white px-6 py-2 rounded-lg"
|
||||
onClick={reloadData}
|
||||
>
|
||||
重新加载
|
||||
</button>
|
||||
<button
|
||||
className="bg-gray-500 text-white px-6 py-2 rounded-lg ml-3"
|
||||
onClick={() => Taro.navigateBack()}
|
||||
>
|
||||
返回上页
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 加载状态 - 使用更好的加载UI
|
||||
if (loading || !goods) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mb-4"></div>
|
||||
<div className="text-gray-600">正在加载商品信息...</div>
|
||||
<div className="text-sm text-gray-400 mt-2">请稍候</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -163,13 +163,21 @@ export async function handleInviteRelation(userId: number): Promise<boolean> {
|
||||
return true // 返回true表示关系已存在
|
||||
}
|
||||
|
||||
// 设置API调用超时
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('API调用超时')), 5000)
|
||||
);
|
||||
|
||||
// 使用新的绑定推荐关系接口
|
||||
await bindRefereeRelation({
|
||||
const apiPromise = bindRefereeRelation({
|
||||
dealerId: inviterId,
|
||||
userId: userId,
|
||||
source: inviteParams.source || 'qrcode',
|
||||
scene: inviteParams.source === 'qrcode' ? `uid_${inviterId}` : `inviter=${inviterId}&source=${inviteParams.source}&t=${inviteParams.t}`
|
||||
})
|
||||
});
|
||||
|
||||
// 等待API调用完成或超时
|
||||
await Promise.race([apiPromise, timeoutPromise]);
|
||||
|
||||
// 标记邀请关系已处理(设置过期时间为7天)
|
||||
Taro.setStorageSync(relationKey, {
|
||||
@@ -185,6 +193,16 @@ export async function handleInviteRelation(userId: number): Promise<boolean> {
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('建立邀请关系失败:', error)
|
||||
|
||||
// 如果是网络错误或超时,不清除邀请参数,允许稍后重试
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
if (errorMessage.includes('超时') || errorMessage.includes('网络')) {
|
||||
console.log('网络问题,保留邀请参数供稍后重试')
|
||||
return false
|
||||
}
|
||||
|
||||
// 其他错误(如业务逻辑错误),清除邀请参数
|
||||
clearInviteParams()
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -329,9 +347,30 @@ export async function checkAndHandleInviteRelation(): Promise<boolean> {
|
||||
}
|
||||
|
||||
console.log('使用用户ID处理邀请关系:', finalUserId)
|
||||
return await handleInviteRelation(parseInt(finalUserId))
|
||||
|
||||
// 设置整体超时保护
|
||||
const timeoutPromise = new Promise<boolean>((_, reject) =>
|
||||
setTimeout(() => reject(new Error('邀请关系处理整体超时')), 6000)
|
||||
);
|
||||
|
||||
const handlePromise = handleInviteRelation(parseInt(finalUserId));
|
||||
|
||||
return await Promise.race([handlePromise, timeoutPromise]);
|
||||
} catch (error) {
|
||||
console.error('检查邀请关系失败:', error)
|
||||
|
||||
// 记录失败次数,避免无限重试
|
||||
const failKey = 'invite_handle_fail_count'
|
||||
const failCount = Taro.getStorageSync(failKey) || 0
|
||||
|
||||
if (failCount >= 3) {
|
||||
console.log('邀请关系处理失败次数过多,清除邀请参数')
|
||||
clearInviteParams()
|
||||
Taro.removeStorageSync(failKey)
|
||||
} else {
|
||||
Taro.setStorageSync(failKey, failCount + 1)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user