Files
template-10584/src/pages/index/index.tsx
赵忠林 e053062c7c Merge branch 'demo' into dev
# Conflicts:
#	src/pages/user/components/UserCard.tsx
2025-09-10 10:10:04 +08:00

318 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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