forked from gxwebsoft/mp-10550
318 lines
10 KiB
TypeScript
318 lines
10 KiB
TypeScript
import Header from './Header';
|
||
import BestSellers from './BestSellers';
|
||
import Taro from '@tarojs/taro';
|
||
import { View, Text } from '@tarojs/components';
|
||
import {useShareAppMessage} from "@tarojs/taro"
|
||
import {useEffect, useState} from "react";
|
||
import {getShopInfo, loginByOpenId} from "@/api/layout";
|
||
import {TenantId} from "@/config/app";
|
||
import {saveStorageByLoginUser} from "@/utils/server";
|
||
import {Sticky} from '@nutui/nutui-react-taro'
|
||
import Menu from "./Menu";
|
||
import Banner from "./Banner";
|
||
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
|
||
import {showNetworkDiagnosis} from "@/utils/networkCheck";
|
||
import {BaseUrl} from "@/config/app";
|
||
import './index.scss'
|
||
|
||
// import GoodsList from "./GoodsList";
|
||
|
||
function Home() {
|
||
// 吸顶状态
|
||
const [stickyStatus, setStickyStatus] = useState<boolean>(false)
|
||
// 页面加载状态
|
||
const [pageLoading, setPageLoading] = useState<boolean>(true)
|
||
// 初始化状态
|
||
const [initStatus, setInitStatus] = useState<{
|
||
shopInfo: boolean;
|
||
userAuth: boolean;
|
||
userLogin: boolean;
|
||
}>({
|
||
shopInfo: false,
|
||
userAuth: false,
|
||
userLogin: false
|
||
})
|
||
|
||
// 检查是否所有初始化都完成
|
||
const checkInitComplete = (newStatus: Partial<typeof initStatus>) => {
|
||
const updatedStatus = { ...initStatus, ...newStatus };
|
||
setInitStatus(updatedStatus);
|
||
|
||
const allComplete = Object.values(updatedStatus).every(status => status === true);
|
||
if (allComplete && pageLoading) {
|
||
console.log('✅ 所有初始化完成,隐藏加载状态');
|
||
setPageLoading(false);
|
||
Taro.hideLoading();
|
||
}
|
||
}
|
||
|
||
useShareAppMessage(() => {
|
||
// 获取当前用户ID,用于生成邀请链接
|
||
const userId = Taro.getStorageSync('UserId');
|
||
|
||
return {
|
||
title: '时里院子市集',
|
||
path: userId ? `/pages/index/index?inviter=${userId}&source=share&t=${Date.now()}` : `/pages/index/index`,
|
||
success: function () {
|
||
console.log('首页分享成功');
|
||
Taro.showToast({
|
||
title: '分享成功',
|
||
icon: 'success',
|
||
duration: 2000
|
||
});
|
||
},
|
||
fail: function () {
|
||
console.log('首页分享失败');
|
||
Taro.showToast({
|
||
title: '分享失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
});
|
||
}
|
||
};
|
||
});
|
||
|
||
// const reloadMore = async () => {
|
||
// setPage(page + 1)
|
||
// }
|
||
|
||
const showAuthModal = () => {
|
||
Taro.showModal({
|
||
title: '授权提示',
|
||
content: '需要获取您的用户信息',
|
||
confirmText: '去授权',
|
||
cancelText: '取消',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
// 用户点击确认,打开授权设置页面
|
||
openSetting();
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
const openSetting = () => {
|
||
// Taro.openSetting:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
|
||
Taro.openSetting({
|
||
success: (res) => {
|
||
if (res.authSetting['scope.userInfo']) {
|
||
// 用户授权成功,可以获取用户信息
|
||
console.log('用户重新授权成功');
|
||
reload();
|
||
} else {
|
||
// 用户拒绝授权,提示授权失败
|
||
console.log('用户拒绝授权');
|
||
checkInitComplete({ userLogin: true });
|
||
Taro.showToast({
|
||
title: '授权失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
console.error('打开设置页面失败:', error);
|
||
checkInitComplete({ userLogin: true });
|
||
}
|
||
});
|
||
};
|
||
|
||
const onSticky = (item: IArguments) => {
|
||
if(item){
|
||
setStickyStatus(!stickyStatus)
|
||
}
|
||
}
|
||
|
||
const reload = () => {
|
||
console.log('开始执行登录流程...');
|
||
Taro.login({
|
||
success: (res) => {
|
||
console.log('微信登录成功,code:', res.code);
|
||
|
||
// 调用后端登录接口
|
||
loginByOpenId({
|
||
code: res.code,
|
||
tenantId: TenantId
|
||
}).then(async data => {
|
||
console.log('后端登录成功:', data);
|
||
if (data) {
|
||
// 保存用户信息到本地存储
|
||
saveStorageByLoginUser(data.access_token, data.user);
|
||
|
||
// 标记登录完成
|
||
checkInitComplete({ userLogin: true });
|
||
|
||
Taro.showToast({
|
||
title: '登录成功',
|
||
icon: 'success',
|
||
duration: 2000
|
||
});
|
||
console.log('✅ 用户登录完成');
|
||
} else {
|
||
throw new Error('登录返回数据为空');
|
||
}
|
||
}).catch(error => {
|
||
console.error('后端登录失败:', error);
|
||
// 即使登录失败也标记为完成,避免一直加载
|
||
checkInitComplete({ userLogin: true });
|
||
Taro.showToast({
|
||
title: '登录失败,请重试',
|
||
icon: 'error',
|
||
duration: 3000
|
||
});
|
||
});
|
||
},
|
||
fail: (error) => {
|
||
console.error('微信登录失败:', error);
|
||
Taro.showToast({
|
||
title: '微信登录失败',
|
||
icon: 'error',
|
||
duration: 3000
|
||
});
|
||
}
|
||
});
|
||
};
|
||
|
||
useEffect(() => {
|
||
console.log('=== 首页初始化开始 ===');
|
||
|
||
// 显示加载提示
|
||
Taro.showLoading({
|
||
title: '加载中...',
|
||
mask: true
|
||
});
|
||
|
||
// 获取站点信息
|
||
console.log('开始获取站点信息...');
|
||
getShopInfo().then((data) => {
|
||
console.log('站点信息获取成功:', data);
|
||
checkInitComplete({ shopInfo: true });
|
||
}).catch((error) => {
|
||
console.error('站点信息获取失败:', error);
|
||
// 即使失败也标记为完成,避免一直加载
|
||
checkInitComplete({ shopInfo: true });
|
||
// 显示错误提示
|
||
Taro.showToast({
|
||
title: '获取站点信息失败',
|
||
icon: 'error',
|
||
duration: 3000
|
||
});
|
||
});
|
||
|
||
// 检查是否有待处理的邀请关系 - 异步处理,不阻塞页面加载
|
||
if (hasPendingInvite()) {
|
||
console.log('检测到待处理的邀请关系')
|
||
// 延迟处理,确保用户信息已加载,并设置超时保护
|
||
setTimeout(async () => {
|
||
try {
|
||
// 设置超时保护,避免长时间等待
|
||
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)
|
||
}
|
||
|
||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||
console.log('开始检查用户授权状态...');
|
||
Taro.getSetting({
|
||
success: (res) => {
|
||
console.log('授权状态检查结果:', res.authSetting);
|
||
checkInitComplete({ userAuth: true });
|
||
|
||
if (res.authSetting['scope.userInfo']) {
|
||
// 用户已经授权过,可以直接获取用户信息
|
||
console.log('✅ 用户已经授权过,开始登录流程');
|
||
reload();
|
||
} else {
|
||
// 用户未授权,需要弹出授权窗口
|
||
console.log('❌ 用户未授权,显示授权弹窗');
|
||
showAuthModal();
|
||
// 即使未授权也标记登录为完成,避免一直加载
|
||
checkInitComplete({ userLogin: true });
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
console.error('获取授权状态失败:', error);
|
||
// 标记为完成,避免一直加载
|
||
checkInitComplete({ userAuth: true, userLogin: true });
|
||
Taro.showToast({
|
||
title: '获取授权状态失败',
|
||
icon: 'error',
|
||
duration: 3000
|
||
});
|
||
}
|
||
});
|
||
// 获取用户信息
|
||
Taro.getUserInfo({
|
||
success: (res) => {
|
||
const avatar = res.userInfo.avatarUrl;
|
||
console.log(avatar, 'avatarUrl')
|
||
}
|
||
});
|
||
}, []);
|
||
|
||
// 如果还在加载中,显示加载页面
|
||
if (pageLoading) {
|
||
return (
|
||
<View className="flex flex-col items-center justify-center min-h-screen bg-gray-50 p-4">
|
||
<View className="text-center">
|
||
<View className="mb-6">
|
||
<View className="animate-spin rounded-full h-16 w-16 border-b-2 border-blue-500 mx-auto"></View>
|
||
</View>
|
||
<View className="text-lg text-gray-700 mb-4">加载中...</View>
|
||
<View className="text-sm text-gray-500 mb-6 space-y-1">
|
||
<Text>站点信息: {initStatus.shopInfo ? '✅ 完成' : '⏳ 加载中'}</Text>
|
||
<Text>用户授权: {initStatus.userAuth ? '✅ 完成' : '⏳ 检查中'}</Text>
|
||
<Text>用户登录: {initStatus.userLogin ? '✅ 完成' : '⏳ 登录中'}</Text>
|
||
</View>
|
||
|
||
{/* 如果加载时间过长,显示帮助按钮 */}
|
||
<View className="space-y-3">
|
||
<View
|
||
className="px-4 py-2 bg-blue-500 text-white rounded-lg text-sm"
|
||
onClick={() => showNetworkDiagnosis(BaseUrl)}
|
||
>
|
||
网络诊断
|
||
</View>
|
||
<View className="text-xs text-gray-400">
|
||
如果长时间无响应,请点击网络诊断
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<Sticky threshold={0} onChange={() => onSticky(arguments)}>
|
||
<Header stickyStatus={stickyStatus}/>
|
||
</Sticky>
|
||
<div className={'flex flex-col mt-12'}>
|
||
<Menu/>
|
||
<Banner/>
|
||
<BestSellers/>
|
||
{/*<GoodsList/>*/}
|
||
</div>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default Home
|