Files
template-10559/src/pages/index/Header.tsx
赵忠林 81ec58523d feat(商品列表): 实现商品列表吸顶效果和分享功能- 添加 Tabs 粘性布局组件,实现吸顶效果- 新增商品分享功能,支持分享给好友
-优化商品列表展示样式,使用瀑布流布局
- 调整商品图片展示方式和点击跳转逻辑- 添加空状态提示,改善用户体验
-修复部分样式问题,提升页面美观度- 移除旧版订单列表相关代码和依赖- 更新页面结构,提高组件复用性
- 添加系统信息获取,适配不同设备屏幕
-优化页面滚动体验,解决滑动冲突问题
2025-10-07 20:10:04 +08:00

244 lines
7.7 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 {useEffect, useState} from "react";
import Taro from '@tarojs/taro';
import {Button, Space, Sticky} from '@nutui/nutui-react-taro'
import {TriangleDown} from '@nutui/icons-react-taro'
import {Avatar, NavBar} from '@nutui/nutui-react-taro'
import {getUserInfo, getWxOpenId} from "@/api/layout";
import {TenantId} from "@/config/app";
import {getOrganization} from "@/api/system/organization";
import {myUserVerify} from "@/api/system/userVerify";
import { useShopInfo } from '@/hooks/useShopInfo';
import {handleInviteRelation, getStoredInviteParams} from "@/utils/invite";
import {View,Text} from '@tarojs/components'
import MySearch from "./MySearch";
import './Header.scss';
const Header = (_: any) => {
// 使用新的useShopInfo Hook
const {
getWebsiteName,
getWebsiteLogo
} = useShopInfo();
const [IsLogin, setIsLogin] = useState<boolean>(true)
const [statusBarHeight, setStatusBarHeight] = useState<number>()
const [stickyStatus, setStickyStatus] = useState<boolean>(false)
const reload = async () => {
Taro.getSystemInfo({
success: (res) => {
setStatusBarHeight(res.statusBarHeight)
},
})
// 注意商店信息现在通过useShopInfo自动管理不需要手动获取
// 获取用户信息
getUserInfo().then((data) => {
if (data) {
setIsLogin(true);
console.log('用户信息>>>', data.phone)
// 保存userId
Taro.setStorageSync('UserId', data.userId)
// 获取openId
if (!data.openid) {
Taro.login({
success: (res) => {
getWxOpenId({code: res.code}).then(() => {
})
}
})
}
// 是否已认证
if (data.certification) {
Taro.setStorageSync('Certification', '1')
}
// 机构ID
Taro.setStorageSync('OrganizationId', data.organizationId)
// 父级机构ID
if (Number(data.organizationId) > 0) {
getOrganization(Number(data.organizationId)).then(res => {
Taro.setStorageSync('OrganizationParentId', res.parentId)
})
}
// 管理员
const isKdy = data.roles?.findIndex(item => item.roleCode == 'admin')
if (isKdy != -1) {
Taro.setStorageSync('RoleName', '管理')
Taro.setStorageSync('RoleCode', 'admin')
return false;
}
// 注册用户
const isUser = data.roles?.findIndex(item => item.roleCode == 'user')
if (isUser != -1) {
Taro.setStorageSync('RoleName', '注册用户')
Taro.setStorageSync('RoleCode', 'user')
return false;
}
}
}).catch(() => {
setIsLogin(false);
console.log('未登录')
});
// 认证信息
myUserVerify({status: 1}).then(data => {
if (data?.realName) {
Taro.setStorageSync('RealName', data.realName)
}
})
}
/* 获取用户手机号 */
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
const {code, encryptedData, iv} = detail
// 防重复登录检查
const loginKey = 'login_in_progress'
const loginInProgress = Taro.getStorageSync(loginKey)
if (loginInProgress && Date.now() - loginInProgress < 5000) { // 5秒内防重
return
}
// 标记登录开始
Taro.setStorageSync(loginKey, Date.now())
// 获取存储的邀请参数
const inviteParams = getStoredInviteParams()
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
Taro.login({
success: function () {
if (code) {
Taro.request({
url: 'https://server.websoft.top/api/wx-login/loginByMpWxPhone',
method: 'POST',
data: {
code,
encryptedData,
iv,
notVerifyPhone: true,
refereeId: refereeId, // 使用解析出的推荐人ID
sceneType: 'save_referee',
tenantId: TenantId
},
header: {
'content-type': 'application/json',
TenantId
},
success: async function (res) {
// 清除登录防重标记
Taro.removeStorageSync('login_in_progress')
if (res.data.code == 1) {
Taro.showToast({
title: res.data.message,
icon: 'error',
duration: 2000
})
return false;
}
// 登录成功
Taro.setStorageSync('access_token', res.data.data.access_token)
Taro.setStorageSync('UserId', res.data.data.user.userId)
setIsLogin(true)
// 处理邀请关系
if (res.data.data.user?.userId) {
try {
await handleInviteRelation(res.data.data.user.userId)
} catch (error) {
console.error('处理邀请关系失败:', error)
}
}
// 重新加载小程序
Taro.reLaunch({
url: '/pages/index/index'
})
},
fail: function() {
// 清除登录防重标记
Taro.removeStorageSync('login_in_progress')
}
})
} else {
console.log('登录失败!')
}
}
})
}
// 处理粘性布局状态变化
const onStickyChange = (isSticky: boolean) => {
setStickyStatus(isSticky)
console.log('Header 粘性状态:', isSticky ? '已固定' : '取消固定')
}
// 获取小程序系统信息
// const getSystemInfo = () => {
// const systemInfo = Taro.getSystemInfoSync()
// // 状态栏高度 + 导航栏高度 (一般为44px)
// return (systemInfo.statusBarHeight || 0) + 44
// }
useEffect(() => {
reload().then()
}, [])
return (
<>
<Sticky
threshold={0}
onChange={onStickyChange}
style={{
zIndex: 1000,
backgroundColor: stickyStatus ? '#03605c' : 'transparent',
transition: 'background-color 0.3s ease',
}}
>
<View className={'header-bg'} style={{
height: !stickyStatus ? '180px' : `${(statusBarHeight || 0) + 44}px`,
paddingBottom: !stickyStatus ? '12px' : '0px'
}}>
{/* 只在非吸顶状态下显示搜索框 */}
{!stickyStatus && <MySearch statusBarHeight={statusBarHeight} />}
</View>
<NavBar
style={{
marginTop: `${statusBarHeight}px`,
marginBottom: '0px',
backgroundColor: 'transparent'
}}
onBackClick={() => {
}}
left={
!IsLogin ? (
<View style={{display: 'flex', alignItems: 'center'}}>
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<Space>
<Avatar
size="22"
src={getWebsiteLogo()}
/>
<Text style={{color: '#ffffff'}}>{getWebsiteName()}</Text>
<TriangleDown size={9} className={'text-white'}/>
</Space>
</Button>
</View>
) : (
<View style={{display: 'flex', alignItems: 'center', gap: '8px'}}>
<Avatar
size="22"
src={getWebsiteLogo()}
/>
<Text className={'text-white'}>{getWebsiteName()}</Text>
<TriangleDown className={'text-white'} size={9}/>
</View>
)}>
{/*<QRLoginButton />*/}
</NavBar>
</Sticky>
</>
)
}
export default Header