feat(user): 更新用户界面和功能实现- 默认 修改 UnifiedQRButton类型为 danger- 更新 Banner 组件使用 getCmsAdByCode 获取广告数据
- 新增 CMS 文章查询接口 getCmsArticleByCode - 调整 UserCard 组件界面样式和逻辑-优化 BestSellers 商品展示组件 - 更新 IsDealer 组件支持网站字段配置 - 移除用户页面部分冗余代码和样式 - 增加主题样式支持和背景装饰元素 - 调整用户相关组件层级和定位样式
This commit is contained in:
@@ -3,15 +3,23 @@ import navTo from "@/utils/common";
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
|
||||
import {useUser} from '@/hooks/useUser'
|
||||
import {useEffect} from "react";
|
||||
import {useEffect, useState} from "react";
|
||||
import {useDealerUser} from "@/hooks/useDealerUser";
|
||||
import {useThemeStyles} from "@/hooks/useTheme";
|
||||
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
||||
import {Config} from "@/api/cms/cmsWebsiteField/model";
|
||||
|
||||
const UserCell = () => {
|
||||
const IsDealer = () => {
|
||||
const themeStyles = useThemeStyles();
|
||||
const [config, setConfig] = useState<Config>()
|
||||
const {isSuperAdmin} = useUser();
|
||||
const {dealerUser} = useDealerUser()
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
configWebsiteField().then(data => {
|
||||
console.log(data)
|
||||
setConfig(data)
|
||||
})
|
||||
}, [])
|
||||
|
||||
/**
|
||||
@@ -20,12 +28,10 @@ const UserCell = () => {
|
||||
if (isSuperAdmin()) {
|
||||
return (
|
||||
<>
|
||||
<View className={'px-4'}>
|
||||
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 25 }}>
|
||||
<Cell
|
||||
className="nutui-cell-clickable"
|
||||
style={{
|
||||
backgroundImage: 'linear-gradient(to right bottom, #e53e3e, #c53030)',
|
||||
}}
|
||||
style={themeStyles.primaryBackground}
|
||||
title={
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
<Setting className={'text-white '} size={16}/>
|
||||
@@ -46,17 +52,15 @@ const UserCell = () => {
|
||||
if (dealerUser) {
|
||||
return (
|
||||
<>
|
||||
<View className={'px-4'}>
|
||||
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 25 }}>
|
||||
<Cell
|
||||
className="nutui-cell-clickable"
|
||||
style={{
|
||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
||||
}}
|
||||
style={themeStyles.primaryBackground}
|
||||
title={
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
<Reward className={'text-orange-100 '} size={16}/>
|
||||
<Text style={{fontSize: '16px'}}
|
||||
className={'pl-3 text-orange-100 font-medium'}>分销中心</Text>
|
||||
className={'pl-3 text-orange-100 font-medium'}>{config?.vipText || '入驻申请'}</Text>
|
||||
{/*<Text className={'text-white opacity-80 pl-3'}>门店核销</Text>*/}
|
||||
</View>
|
||||
}
|
||||
@@ -73,17 +77,15 @@ const UserCell = () => {
|
||||
*/
|
||||
return (
|
||||
<>
|
||||
<View className={'px-4'}>
|
||||
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 25 }}>
|
||||
<Cell
|
||||
className="nutui-cell-clickable"
|
||||
style={{
|
||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
||||
}}
|
||||
style={themeStyles.primaryBackground}
|
||||
title={
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
<Reward className={'text-orange-100 '} size={16}/>
|
||||
<Text style={{fontSize: '16px'}} className={'pl-3 text-orange-100 font-medium'}>开通VIP</Text>
|
||||
<Text className={'text-white opacity-80 pl-3'}>享优惠</Text>
|
||||
<Text style={{fontSize: '16px'}} className={'pl-3 text-orange-100 font-medium'}>{config?.vipText || '开通VIP'}</Text>
|
||||
<Text className={'text-white opacity-80 pl-3'}>{config?.vipComments || '享优惠'}</Text>
|
||||
</View>
|
||||
}
|
||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||
@@ -93,4 +95,4 @@ const UserCell = () => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default UserCell
|
||||
export default IsDealer
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Avatar, Tag, Space, Button} from '@nutui/nutui-react-taro'
|
||||
import {View, Text, Image} from '@tarojs/components'
|
||||
import {Avatar, Tag, Space} from '@nutui/nutui-react-taro'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
||||
import Taro from '@tarojs/taro';
|
||||
import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
|
||||
@@ -10,6 +10,7 @@ import {useUser} from "@/hooks/useUser";
|
||||
import {useUserData} from "@/hooks/useUserData";
|
||||
import {getStoredInviteParams} from "@/utils/invite";
|
||||
import UnifiedQRButton from "@/components/UnifiedQRButton";
|
||||
import {useThemeStyles} from "@/hooks/useTheme";
|
||||
|
||||
const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
const {data, refresh} = useUserData()
|
||||
@@ -17,6 +18,8 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
||||
const [userInfo, setUserInfo] = useState<User>()
|
||||
|
||||
const themeStyles = useThemeStyles();
|
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = async () => {
|
||||
await refresh()
|
||||
@@ -95,7 +98,6 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const openSetting = () => {
|
||||
// Taro.openSetting:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
|
||||
Taro.openSetting({
|
||||
@@ -118,6 +120,11 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
|
||||
const {code, encryptedData, iv} = detail
|
||||
|
||||
// 判断用户是否已登录
|
||||
if(IsLogin){
|
||||
return navTo(`/user/profile/profile`)
|
||||
}
|
||||
|
||||
// 获取存储的邀请参数
|
||||
const inviteParams = getStoredInviteParams()
|
||||
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||
@@ -165,34 +172,19 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<View className={'header-bg pt-20'}>
|
||||
<View className={'p-4'}>
|
||||
<View className={'pt-14'}>
|
||||
{/* 使用相对定位容器,让个人资料图片可以绝对定位在右上角 */}
|
||||
<View className="relative">
|
||||
<View className="relative z-20">
|
||||
<View
|
||||
className={'user-card w-full flex flex-col justify-around rounded-xl'}
|
||||
style={{
|
||||
background: 'linear-gradient(to bottom, #ffffff, #ffffff)',
|
||||
height: '170px',
|
||||
}}
|
||||
>
|
||||
<View className={'user-card-header flex w-full justify-between items-center pt-4'}>
|
||||
<View className={'flex items-center mx-4'}>
|
||||
{
|
||||
IsLogin ? (
|
||||
<Avatar size="large"
|
||||
src={userInfo?.avatar || 'https://oss.wsdns.cn/20250623/62f830b85edb4a7293b8948c25e6f987.jpeg'}
|
||||
shape="round"/>
|
||||
) : (
|
||||
<Button className={'text-black'} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
|
||||
<Avatar size="large"
|
||||
src={userInfo?.avatar || 'https://oss.wsdns.cn/20250623/62f830b85edb4a7293b8948c25e6f987.jpeg'}
|
||||
shape="round"/>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
<View className={'flex items-center mx-4'} onClick={handleGetPhoneNumber}>
|
||||
<Avatar size="large"
|
||||
src={userInfo?.avatar || ''}
|
||||
shape="round"/>
|
||||
<View className={'user-info flex flex-col px-2'}>
|
||||
<View className={'py-1 text-black font-bold'}>{getDisplayName()}</View>
|
||||
<View className={'py-1 text-white font-bold'}>{getDisplayName()}</View>
|
||||
{IsLogin ? (
|
||||
<View className={'grade text-xs py-1'}>
|
||||
<Tag type="success" round>
|
||||
@@ -210,7 +202,7 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
}}>
|
||||
{/*统一扫码入口 - 支持登录和核销*/}
|
||||
<UnifiedQRButton
|
||||
text="扫码"
|
||||
text="扫一扫"
|
||||
size="small"
|
||||
onSuccess={(result) => {
|
||||
console.log('统一扫码成功:', result);
|
||||
@@ -229,47 +221,31 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
||||
/>
|
||||
</Space>
|
||||
</View>
|
||||
<View className={'flex justify-around mt-1'}>
|
||||
<View className={'item flex justify-center flex-col items-center'}
|
||||
onClick={() => navTo('/user/wallet/wallet', true)}>
|
||||
<Text className={'text-sm text-gray-500'}>余额</Text>
|
||||
<Text className={'text-xl'}>{data?.balance || '0.00'}</Text>
|
||||
</View>
|
||||
<View className={'item flex justify-center flex-col items-center'}>
|
||||
<Text className={'text-sm text-gray-500'}>积分</Text>
|
||||
<Text className={'text-xl'}>{data?.points || 0}</Text>
|
||||
</View>
|
||||
<View className={'item flex justify-center flex-col items-center'}
|
||||
onClick={() => navTo('/user/coupon/index', true)}>
|
||||
<Text className={'text-sm text-gray-500'}>优惠券</Text>
|
||||
<Text className={'text-xl'}>{data?.coupons || 0}</Text>
|
||||
</View>
|
||||
<View className={'item flex justify-center flex-col items-center'}
|
||||
onClick={() => navTo('/user/gift/index', true)}>
|
||||
<Text className={'text-sm text-gray-500'}>礼品卡</Text>
|
||||
<Text className={'text-xl'}>{data?.giftCards || 0}</Text>
|
||||
<View className={'py-2'}>
|
||||
<View className={'flex justify-around mt-1'}>
|
||||
<View className={'item flex justify-center flex-col items-center'}
|
||||
onClick={() => navTo('/user/wallet/wallet', true)}>
|
||||
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>余额</Text>
|
||||
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.balance || '0.00'}</Text>
|
||||
</View>
|
||||
<View className={'item flex justify-center flex-col items-center'}>
|
||||
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>积分</Text>
|
||||
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.points || 0}</Text>
|
||||
</View>
|
||||
<View className={'item flex justify-center flex-col items-center'}
|
||||
onClick={() => navTo('/user/coupon/index', true)}>
|
||||
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>优惠券</Text>
|
||||
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.coupons || 0}</Text>
|
||||
</View>
|
||||
<View className={'item flex justify-center flex-col items-center'}
|
||||
onClick={() => navTo('/user/gift/index', true)}>
|
||||
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>礼品卡</Text>
|
||||
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.giftCards || 0}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 个人资料图片,定位在右上角 */}
|
||||
<View
|
||||
className="absolute top-0 right-0 overflow-hidden"
|
||||
style={{
|
||||
borderRadius: "0 0.75rem 0 0"
|
||||
}}
|
||||
onClick={() => navTo('/user/profile/profile', true)}
|
||||
>
|
||||
<Image
|
||||
src="https://oss.wsdns.cn/20250913/7c3de38b377344b89131aba40214f63f.png"
|
||||
style={{
|
||||
width: "200rpx"
|
||||
}}
|
||||
mode="widthFix"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@ const UserCell = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className={'px-4'}>
|
||||
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 20 }}>
|
||||
|
||||
<Cell.Group divider={true} description={
|
||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
|
||||
@@ -138,6 +138,53 @@ const UserCell = () => {
|
||||
</Grid>
|
||||
</ConfigProvider>
|
||||
</View>
|
||||
{/*<View className="bg-white mx-4 mt-4 rounded-xl">*/}
|
||||
{/* <View className="font-semibold text-gray-800 pt-4 pl-4">账号管理</View>*/}
|
||||
{/* <ConfigProvider>*/}
|
||||
{/* <Grid*/}
|
||||
{/* columns={4}*/}
|
||||
{/* className="no-border-grid"*/}
|
||||
{/* style={{*/}
|
||||
{/* '--nutui-grid-border-color': 'transparent',*/}
|
||||
{/* '--nutui-grid-item-border-width': '0px',*/}
|
||||
{/* border: 'none'*/}
|
||||
{/* } as React.CSSProperties}*/}
|
||||
{/* >*/}
|
||||
{/* <Grid.Item text="账号安全" onClick={() => navTo('/user/profile/profile', true)}>*/}
|
||||
{/* <View className="text-center">*/}
|
||||
{/* <View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
||||
{/* <ShoppingAdd color="#3b82f6" size="20"/>*/}
|
||||
{/* </View>*/}
|
||||
{/* </View>*/}
|
||||
{/* </Grid.Item>*/}
|
||||
|
||||
{/* <Grid.Item text="切换主题" onClick={() => navTo('/user/theme/index', true)}>*/}
|
||||
{/* <View className="text-center">*/}
|
||||
{/* <View className="w-12 h-12 bg-emerald-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
||||
{/* <Location color="#3b82f6" size="20"/>*/}
|
||||
{/* </View>*/}
|
||||
{/* </View>*/}
|
||||
{/* </Grid.Item>*/}
|
||||
|
||||
{/* <Grid.Item text={'关于我们'} onClick={() => navTo('/user/about/index')}>*/}
|
||||
{/* <View className="text-center">*/}
|
||||
{/* <View className="w-12 h-12 bg-amber-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
||||
{/* <Tips className={'text-amber-500'} size="20"/>*/}
|
||||
{/* </View>*/}
|
||||
{/* </View>*/}
|
||||
{/* </Grid.Item>*/}
|
||||
|
||||
{/* <Grid.Item text={'安全退出'} onClick={onLogout}>*/}
|
||||
{/* <View className="text-center">*/}
|
||||
{/* <View className="w-12 h-12 bg-pink-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
||||
{/* <Logout className={'text-pink-500'} size="20"/>*/}
|
||||
{/* </View>*/}
|
||||
{/* </View>*/}
|
||||
{/* </Grid.Item>*/}
|
||||
|
||||
{/* </Grid>*/}
|
||||
{/* </ConfigProvider>*/}
|
||||
{/*</View>*/}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ function UserOrder() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className={'px-4 pb-2'}>
|
||||
<View className={'px-4 pb-2 z-30 relative'} style={{ marginTop: '8px' }}>
|
||||
<View
|
||||
className={'user-card w-full flex flex-col justify-around rounded-xl shadow-sm'}
|
||||
style={{
|
||||
|
||||
@@ -4,14 +4,17 @@ import UserCard from "./components/UserCard";
|
||||
import UserOrder from "./components/UserOrder";
|
||||
import UserFooter from "./components/UserFooter";
|
||||
import {useUserData} from "@/hooks/useUserData";
|
||||
import {View} from '@tarojs/components';
|
||||
import './user.scss'
|
||||
import IsDealer from "./components/IsDealer";
|
||||
import {useThemeStyles} from "@/hooks/useTheme";
|
||||
import UserGrid from "@/pages/user/components/UserGrid";
|
||||
|
||||
function User() {
|
||||
|
||||
const { refresh } = useUserData()
|
||||
const {refresh} = useUserData()
|
||||
const userCardRef = useRef<any>()
|
||||
const themeStyles = useThemeStyles();
|
||||
|
||||
// 下拉刷新处理
|
||||
const handleRefresh = async () => {
|
||||
@@ -30,15 +33,30 @@ function User() {
|
||||
onRefresh={handleRefresh}
|
||||
headHeight={60}
|
||||
>
|
||||
<div className={'w-full'} style={{
|
||||
background: 'linear-gradient(to bottom, #e9fff2, #f9fafb)'
|
||||
}}>
|
||||
<UserCard ref={userCardRef}/>
|
||||
<UserOrder/>
|
||||
<IsDealer/>
|
||||
<UserGrid/>
|
||||
<UserFooter/>
|
||||
</div>
|
||||
{/* 装饰性背景 */}
|
||||
<View className={'h-64 w-full fixed top-0 z-0'} style={themeStyles.primaryBackground}>
|
||||
{/* 装饰性背景元素 - 小程序兼容版本 */}
|
||||
<View className="absolute w-32 h-32 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||
top: '-16px',
|
||||
right: '-16px'
|
||||
}}></View>
|
||||
<View className="absolute w-24 h-24 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||
bottom: '-12px',
|
||||
left: '-12px'
|
||||
}}></View>
|
||||
<View className="absolute w-16 h-16 rounded-full" style={{
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.05)',
|
||||
top: '60px',
|
||||
left: '120px'
|
||||
}}></View>
|
||||
</View>
|
||||
<UserCard ref={userCardRef}/>
|
||||
<UserOrder/>
|
||||
<IsDealer/>
|
||||
<UserGrid/>
|
||||
<UserFooter/>
|
||||
</PullToRefresh>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user