feat(user): 更新用户界面和功能实现- 默认 修改 UnifiedQRButton类型为 danger- 更新 Banner 组件使用 getCmsAdByCode 获取广告数据
- 新增 CMS 文章查询接口 getCmsArticleByCode - 调整 UserCard 组件界面样式和逻辑-优化 BestSellers 商品展示组件 - 更新 IsDealer 组件支持网站字段配置 - 移除用户页面部分冗余代码和样式 - 增加主题样式支持和背景装饰元素 - 调整用户相关组件层级和定位样式
This commit is contained in:
@@ -102,7 +102,7 @@ export async function getCmsAd(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据id查询广告位
|
* 根据code查询广告位
|
||||||
*/
|
*/
|
||||||
export async function getCmsAdByCode(code: string) {
|
export async function getCmsAdByCode(code: string) {
|
||||||
const res = await request.get<ApiResult<CmsAd>>(
|
const res = await request.get<ApiResult<CmsAd>>(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PageParam } from '@/api/index';
|
import type { PageParam } from '@/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 广告位
|
* 广告位
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type {ApiResult, PageResult} from '@/api/index';
|
import type {ApiResult, PageResult} from '@/api';
|
||||||
import type {CmsArticle, CmsArticleParam} from './model';
|
import type {CmsArticle, CmsArticleParam} from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,3 +204,15 @@ export async function getByIds(params?: CmsArticleParam) {
|
|||||||
return Promise.reject(new Error(res.message));
|
return Promise.reject(new Error(res.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据code查询文章
|
||||||
|
*/
|
||||||
|
export async function getCmsArticleByCode(code: string) {
|
||||||
|
const res = await request.get<ApiResult<CmsArticle>>(
|
||||||
|
'/cms/cms-article/getByCode/' + code
|
||||||
|
);
|
||||||
|
if (res.code === 0 && res.data) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
return Promise.reject(new Error(res.message));
|
||||||
|
}
|
||||||
|
|||||||
@@ -55,4 +55,6 @@ export interface Config {
|
|||||||
email?: string;
|
email?: string;
|
||||||
loginTitle?: string;
|
loginTitle?: string;
|
||||||
sysLogo?: string;
|
sysLogo?: string;
|
||||||
|
vipText?: string;
|
||||||
|
vipComments?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,14 +111,14 @@ export default {
|
|||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
pagePath: "pages/index/index",
|
pagePath: "pages/index/index",
|
||||||
iconPath: "assets/tabbar/logo.png",
|
iconPath: "assets/tabbar/home.png",
|
||||||
selectedIconPath: "assets/tabbar/logo.png",
|
selectedIconPath: "assets/tabbar/home-active.png",
|
||||||
text: "首页",
|
text: "首页",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pagePath: "pages/cms/category/index",
|
pagePath: "pages/cms/category/index",
|
||||||
iconPath: "assets/tabbar/tv.png",
|
iconPath: "assets/tabbar/category.png",
|
||||||
selectedIconPath: "assets/tabbar/tv-active.png",
|
selectedIconPath: "assets/tabbar/category-active.png",
|
||||||
text: "基地生活",
|
text: "基地生活",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
BIN
src/assets/tabbar/category-active.png
Normal file
BIN
src/assets/tabbar/category-active.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
src/assets/tabbar/category.png
Normal file
BIN
src/assets/tabbar/category.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.3 KiB |
@@ -29,7 +29,7 @@ export interface UnifiedQRButtonProps {
|
|||||||
* 支持登录和核销两种类型的二维码扫描
|
* 支持登录和核销两种类型的二维码扫描
|
||||||
*/
|
*/
|
||||||
const UnifiedQRButton: React.FC<UnifiedQRButtonProps> = ({
|
const UnifiedQRButton: React.FC<UnifiedQRButtonProps> = ({
|
||||||
type = 'default',
|
type = 'danger',
|
||||||
size = 'small',
|
size = 'small',
|
||||||
text = '扫码',
|
text = '扫码',
|
||||||
showIcon = true,
|
showIcon = true,
|
||||||
|
|||||||
@@ -3,36 +3,35 @@ import {View} from '@tarojs/components'
|
|||||||
import {Swiper} from '@nutui/nutui-react-taro'
|
import {Swiper} from '@nutui/nutui-react-taro'
|
||||||
import {CmsAd} from "@/api/cms/cmsAd/model";
|
import {CmsAd} from "@/api/cms/cmsAd/model";
|
||||||
import {Image} from '@nutui/nutui-react-taro'
|
import {Image} from '@nutui/nutui-react-taro'
|
||||||
import {getCmsAd} from "@/api/cms/cmsAd";
|
import {getCmsAdByCode} from "@/api/cms/cmsAd";
|
||||||
import navTo from "@/utils/common";
|
import navTo from "@/utils/common";
|
||||||
import {ShopGoods} from "@/api/shop/shopGoods/model";
|
import {pageCmsArticle} from "@/api/cms/cmsArticle";
|
||||||
import {listShopGoods} from "@/api/shop/shopGoods";
|
import {CmsArticle} from "@/api/cms/cmsArticle/model";
|
||||||
|
|
||||||
|
|
||||||
const MyPage = () => {
|
const MyPage = () => {
|
||||||
const [carouselData, setCarouselData] = useState<CmsAd>()
|
const [carouselData, setCarouselData] = useState<CmsAd>()
|
||||||
// const [hotToday, setHotToday] = useState<CmsAd>()
|
const [hotToday, setHotToday] = useState<CmsAd>()
|
||||||
// const [groupBuy, setGroupBuy] = useState<CmsAd>()
|
const [item, setItem] = useState<CmsArticle>()
|
||||||
const [hotGoods, setHotGoods] = useState<ShopGoods[]>([])
|
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const loadData = () => {
|
const loadData = async () => {
|
||||||
// 轮播图
|
// 轮播图
|
||||||
getCmsAd(439).then(data => {
|
const flash = await getCmsAdByCode('flash')
|
||||||
setCarouselData(data)
|
|
||||||
})
|
|
||||||
// 今日热卖素材(上层图片)
|
|
||||||
// getCmsAd(444).then(data => {
|
|
||||||
// setHotToday(data)
|
|
||||||
// })
|
|
||||||
// 社区拼团素材(下层图片)
|
|
||||||
// getCmsAd(445).then(data => {
|
|
||||||
// setGroupBuy(data)
|
|
||||||
// })
|
|
||||||
// 今日热卖
|
// 今日热卖
|
||||||
listShopGoods({categoryId: 4424, limit: 2}).then(data => {
|
const hotToday = await getCmsAdByCode('hot_today')
|
||||||
setHotGoods(data)
|
// 时里动态
|
||||||
})
|
const news = await pageCmsArticle({limit:1,recommend:1})
|
||||||
|
// 赋值
|
||||||
|
if(flash){
|
||||||
|
setCarouselData(flash)
|
||||||
|
}
|
||||||
|
if(hotToday){
|
||||||
|
setHotToday(hotToday)
|
||||||
|
}
|
||||||
|
if(news && news.list.length > 0){
|
||||||
|
setItem(news.list[0])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -77,12 +76,12 @@ const MyPage = () => {
|
|||||||
height: '110px'
|
height: '110px'
|
||||||
}}>
|
}}>
|
||||||
{
|
{
|
||||||
hotGoods.map(item => (
|
hotToday?.imageList?.map(item => (
|
||||||
<View className={'item flex flex-col mr-4'}>
|
<View className={'item flex flex-col mr-4'}>
|
||||||
<Image
|
<Image
|
||||||
width={70}
|
width={70}
|
||||||
height={70}
|
height={70}
|
||||||
src={item.image}
|
src={item.url}
|
||||||
mode={'scaleToFill'}
|
mode={'scaleToFill'}
|
||||||
lazyLoad={false}
|
lazyLoad={false}
|
||||||
style={{
|
style={{
|
||||||
@@ -90,7 +89,7 @@ const MyPage = () => {
|
|||||||
}}
|
}}
|
||||||
onClick={() => navTo('/shop/category/index?id=4424')}
|
onClick={() => navTo('/shop/category/index?id=4424')}
|
||||||
/>
|
/>
|
||||||
<View className={'text-xs py-2'}>到手价¥{item.price}</View>
|
<View className={'text-xs py-2 text-orange-600 whitespace-nowrap'}>{item.title || '到手价¥9.9'}</View>
|
||||||
</View>
|
</View>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -103,14 +102,14 @@ const MyPage = () => {
|
|||||||
<View className={'rounded-lg px-3 pb-3'}>
|
<View className={'rounded-lg px-3 pb-3'}>
|
||||||
<Image
|
<Image
|
||||||
width={'100%'}
|
width={'100%'}
|
||||||
height={100}
|
height={106}
|
||||||
src={'https://oss.wsdns.cn/20250919/941c99899e694a7798cab3bb28f1f238.png?x-oss-process=image/resize,m_fixed,w_750/quality,Q_90'}
|
src={item?.image}
|
||||||
mode={'scaleToFill'}
|
mode={'scaleToFill'}
|
||||||
lazyLoad={false}
|
lazyLoad={false}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: '4px'
|
borderRadius: '4px'
|
||||||
}}
|
}}
|
||||||
onClick={() => navTo('cms/detail/index?id=10109')}
|
onClick={() => navTo('cms/detail/index?id=' + item?.articleId)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,70 +1,37 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {Image, Swiper, SwiperItem, Empty} from '@nutui/nutui-react-taro'
|
import {Image} from '@nutui/nutui-react-taro'
|
||||||
import {Share} from '@nutui/icons-react-taro'
|
import {Share} from '@nutui/icons-react-taro'
|
||||||
import {View, Text} from '@tarojs/components';
|
import {View, Text} from '@tarojs/components';
|
||||||
import Taro from "@tarojs/taro";
|
import Taro from "@tarojs/taro";
|
||||||
import {Tabs} from '@nutui/nutui-react-taro'
|
|
||||||
import {ShopGoods} from "@/api/shop/shopGoods/model";
|
import {ShopGoods} from "@/api/shop/shopGoods/model";
|
||||||
import {pageShopGoods} from "@/api/shop/shopGoods";
|
import {pageShopGoods} from "@/api/shop/shopGoods";
|
||||||
|
|
||||||
|
|
||||||
const BestSellers = () => {
|
const BestSellers = () => {
|
||||||
const [tab1value, setTab1value] = useState<string | number>('0')
|
|
||||||
const [list, setList] = useState<ShopGoods[]>([])
|
const [list, setList] = useState<ShopGoods[]>([])
|
||||||
const [goods, setGoods] = useState<ShopGoods | null>(null)
|
const [goods, setGoods] = useState<ShopGoods>()
|
||||||
// 轮播图固定高度,可根据需求调整
|
|
||||||
const SWIPER_HEIGHT = 180;
|
|
||||||
|
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
pageShopGoods({}).then(res => {
|
pageShopGoods({}).then(res => {
|
||||||
const processGoodsItem = (item: ShopGoods) => {
|
setList(res?.list || []);
|
||||||
const pics: string[] = [];
|
})
|
||||||
// 添加主图
|
|
||||||
if (item.image) {
|
|
||||||
pics.push(item.image);
|
|
||||||
}
|
|
||||||
// 处理附加图片
|
|
||||||
if (item.files) {
|
|
||||||
try {
|
|
||||||
// 解析文件字符串为对象
|
|
||||||
const files = typeof item.files === "string"
|
|
||||||
? JSON.parse(item.files)
|
|
||||||
: item.files;
|
|
||||||
|
|
||||||
// 收集所有图片URL
|
|
||||||
Object.values(files).forEach(file => {
|
|
||||||
if (file?.url) {
|
|
||||||
pics.push(file.url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('解析文件失败:', error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 返回新对象,避免直接修改原对象
|
|
||||||
return {...item, pics};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理商品列表
|
|
||||||
const goods = (res?.list || []).map(processGoodsItem);
|
|
||||||
setList(goods);
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('获取商品列表失败:', err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理分享点击
|
// 处理分享点击
|
||||||
const handleShare = (item: ShopGoods) => {
|
const handleShare = (item: ShopGoods) => {
|
||||||
setGoods(item);
|
setGoods(item);
|
||||||
|
|
||||||
|
console.log(goods)
|
||||||
|
|
||||||
// 显示分享选项菜单
|
// 显示分享选项菜单
|
||||||
Taro.showActionSheet({
|
Taro.showActionSheet({
|
||||||
itemList: ['分享给好友'],
|
itemList: ['分享给好友'],
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.tapIndex === 0) {
|
if (res.tapIndex === 0) {
|
||||||
|
// 分享给好友 - 触发转发
|
||||||
Taro.showShareMenu({
|
Taro.showShareMenu({
|
||||||
withShareTicket: true,
|
withShareTicket: true,
|
||||||
success: () => {
|
success: () => {
|
||||||
|
// 提示用户点击右上角分享
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '请点击右上角分享给好友',
|
title: '请点击右上角分享给好友',
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
@@ -81,135 +48,56 @@ const BestSellers = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reload();
|
reload()
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
// 配置分享内容
|
// 注意:不在这里配置分享,避免与首页分享冲突
|
||||||
Taro.useShareAppMessage(() => {
|
// 商品分享应该在商品详情页处理,首页分享应该分享首页本身
|
||||||
if (goods) {
|
|
||||||
return {
|
|
||||||
title: goods.name,
|
|
||||||
path: `/shop/goodsDetail/index?id=${goods.goodsId}`,
|
|
||||||
imageUrl: goods.image || ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
title: '热销商品',
|
|
||||||
path: '/pages/index/index'
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className={'py-3'}>
|
<>
|
||||||
<View className={'flex flex-col justify-between items-center rounded-lg px-2'}>
|
<View className={'py-3'}>
|
||||||
<Tabs
|
<View className={'flex flex-col justify-between items-center rounded-lg px-2'}>
|
||||||
value={tab1value}
|
{list?.map((item, index) => {
|
||||||
className={'w-full'}
|
return (
|
||||||
onChange={(value) => {
|
<View key={index} className={'flex flex-col rounded-lg bg-white shadow-sm w-full mb-5'}>
|
||||||
setTab1value(value)
|
<Image src={item.image} mode={'aspectFit'} lazyLoad={false}
|
||||||
}}
|
radius="10px 10px 0 0" height="180"
|
||||||
style={{
|
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
|
||||||
backgroundColor: '#fff',
|
<View className={'flex flex-col p-2 rounded-lg'}>
|
||||||
}}
|
<View>
|
||||||
activeType="smile"
|
<View className={'car-no text-sm'}>{item.name}</View>
|
||||||
>
|
<View className={'flex justify-between text-xs py-1'}>
|
||||||
<Tabs.TabPane title="今日主推">
|
<Text className={'text-orange-500'}>{item.comments}</Text>
|
||||||
</Tabs.TabPane>
|
<Text className={'text-gray-400'}>已售 {item.sales}</Text>
|
||||||
<Tabs.TabPane title="即将到期">
|
</View>
|
||||||
</Tabs.TabPane>
|
<View className={'flex justify-between items-center py-2'}>
|
||||||
<Tabs.TabPane title="活动预告">
|
<View className={'flex text-red-500 text-xl items-baseline'}>
|
||||||
</Tabs.TabPane>
|
<Text className={'text-xs'}>¥</Text>
|
||||||
</Tabs>
|
<Text className={'font-bold text-2xl'}>{item.price}</Text>
|
||||||
|
</View>
|
||||||
{tab1value == '0' && list?.map((item) => (
|
<View className={'buy-btn'}>
|
||||||
<View
|
<View className={'cart-icon items-center hidden'}>
|
||||||
key={item.goodsId || item.id} // 使用商品唯一ID作为key
|
<View
|
||||||
className={'flex flex-col rounded-lg bg-white shadow-sm w-full mb-5'}
|
className={'flex flex-col justify-center items-center text-white px-3 gap-1 text-nowrap whitespace-nowrap cursor-pointer'}
|
||||||
>
|
onClick={() => handleShare(item)}
|
||||||
{/* 轮播图组件 */}
|
>
|
||||||
{item.pics && item.pics.length > 0 ? (
|
<Share size={20}/>
|
||||||
<Swiper
|
</View>
|
||||||
defaultValue={0}
|
</View>
|
||||||
height={SWIPER_HEIGHT}
|
<Text className={'text-white pl-4 pr-5'}
|
||||||
indicator
|
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}>购买
|
||||||
className="swiper-container"
|
</Text>
|
||||||
autoPlay
|
|
||||||
interval={3000}
|
|
||||||
>
|
|
||||||
{item.pics.map((pic, picIndex) => (
|
|
||||||
<SwiperItem key={picIndex}>
|
|
||||||
<Image
|
|
||||||
radius="12px 12px 0 0"
|
|
||||||
height={SWIPER_HEIGHT}
|
|
||||||
src={pic}
|
|
||||||
mode={'aspectFill'} // 使用aspectFill保持比例并填充容器
|
|
||||||
lazyLoad
|
|
||||||
onClick={() => Taro.navigateTo({
|
|
||||||
url: `/shop/goodsDetail/index?id=${item.goodsId}`
|
|
||||||
})}
|
|
||||||
className="swiper-image"
|
|
||||||
/>
|
|
||||||
</SwiperItem>
|
|
||||||
))}
|
|
||||||
</Swiper>
|
|
||||||
) : (
|
|
||||||
// 没有图片时显示占位图
|
|
||||||
<View className="no-image-placeholder" style={{height: `${SWIPER_HEIGHT}px`}}>
|
|
||||||
<Text className="placeholder-text">暂无图片</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<View className={'flex flex-col p-2 rounded-lg'}>
|
|
||||||
<View>
|
|
||||||
<View className={'car-no text-sm'}>{item.name}</View>
|
|
||||||
<View className={'flex justify-between text-xs py-1'}>
|
|
||||||
<Text className={'text-orange-500'}>{item.comments}</Text>
|
|
||||||
<Text className={'text-gray-400'}>已售 {item.sales}</Text>
|
|
||||||
</View>
|
|
||||||
<View className={'flex justify-between items-center py-2'}>
|
|
||||||
<View className={'flex text-red-500 text-xl items-baseline'}>
|
|
||||||
<Text className={'text-xs'}>¥</Text>
|
|
||||||
<Text className={'font-bold text-2xl'}>{item.price}</Text>
|
|
||||||
</View>
|
|
||||||
<View className={'buy-btn'}>
|
|
||||||
<View className={'cart-icon flex items-center hidden'}>
|
|
||||||
<View
|
|
||||||
className={'flex flex-col justify-center items-center text-white px-3 gap-1 text-nowrap whitespace-nowrap cursor-pointer'}
|
|
||||||
onClick={() => handleShare(item)}
|
|
||||||
>
|
|
||||||
<Share size={20}/>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<Text
|
|
||||||
className={'text-white pl-5 pr-5'}
|
|
||||||
onClick={() => Taro.navigateTo({
|
|
||||||
url: `/shop/goodsDetail/index?id=${item.goodsId}`
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
购买
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
)
|
||||||
</View>
|
})}
|
||||||
))}
|
</View>
|
||||||
|
|
||||||
{
|
|
||||||
tab1value == '1' && <Empty description="暂无相关商品" style={{
|
|
||||||
background: 'transparent',
|
|
||||||
}}/>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
tab1value == '2' && <Empty description="暂无相关商品" style={{
|
|
||||||
background: 'transparent',
|
|
||||||
}}/>
|
|
||||||
}
|
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BestSellers
|
export default BestSellers
|
||||||
|
|||||||
@@ -3,15 +3,23 @@ import navTo from "@/utils/common";
|
|||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
|
import {ArrowRight, Reward, Setting} from '@nutui/icons-react-taro'
|
||||||
import {useUser} from '@/hooks/useUser'
|
import {useUser} from '@/hooks/useUser'
|
||||||
import {useEffect} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {useDealerUser} from "@/hooks/useDealerUser";
|
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 {isSuperAdmin} = useUser();
|
||||||
const {dealerUser} = useDealerUser()
|
const {dealerUser} = useDealerUser()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
configWebsiteField().then(data => {
|
||||||
|
console.log(data)
|
||||||
|
setConfig(data)
|
||||||
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,12 +28,10 @@ const UserCell = () => {
|
|||||||
if (isSuperAdmin()) {
|
if (isSuperAdmin()) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View className={'px-4'}>
|
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 25 }}>
|
||||||
<Cell
|
<Cell
|
||||||
className="nutui-cell-clickable"
|
className="nutui-cell-clickable"
|
||||||
style={{
|
style={themeStyles.primaryBackground}
|
||||||
backgroundImage: 'linear-gradient(to right bottom, #e53e3e, #c53030)',
|
|
||||||
}}
|
|
||||||
title={
|
title={
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
<Setting className={'text-white '} size={16}/>
|
<Setting className={'text-white '} size={16}/>
|
||||||
@@ -46,17 +52,15 @@ const UserCell = () => {
|
|||||||
if (dealerUser) {
|
if (dealerUser) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View className={'px-4'}>
|
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 25 }}>
|
||||||
<Cell
|
<Cell
|
||||||
className="nutui-cell-clickable"
|
className="nutui-cell-clickable"
|
||||||
style={{
|
style={themeStyles.primaryBackground}
|
||||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
|
||||||
}}
|
|
||||||
title={
|
title={
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
<Reward className={'text-orange-100 '} size={16}/>
|
<Reward className={'text-orange-100 '} size={16}/>
|
||||||
<Text style={{fontSize: '16px'}}
|
<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>*/}
|
{/*<Text className={'text-white opacity-80 pl-3'}>门店核销</Text>*/}
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
@@ -73,17 +77,15 @@ const UserCell = () => {
|
|||||||
*/
|
*/
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View className={'px-4'}>
|
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 25 }}>
|
||||||
<Cell
|
<Cell
|
||||||
className="nutui-cell-clickable"
|
className="nutui-cell-clickable"
|
||||||
style={{
|
style={themeStyles.primaryBackground}
|
||||||
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
|
||||||
}}
|
|
||||||
title={
|
title={
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
<Reward className={'text-orange-100 '} size={16}/>
|
<Reward className={'text-orange-100 '} size={16}/>
|
||||||
<Text style={{fontSize: '16px'}} className={'pl-3 text-orange-100 font-medium'}>开通VIP</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'}>享优惠</Text>
|
<Text className={'text-white opacity-80 pl-3'}>{config?.vipComments || '享优惠'}</Text>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
extra={<ArrowRight color="#cccccc" size={18}/>}
|
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 {Avatar, Tag, Space} from '@nutui/nutui-react-taro'
|
||||||
import {View, Text, Image} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
|
import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
|
||||||
@@ -10,6 +10,7 @@ import {useUser} from "@/hooks/useUser";
|
|||||||
import {useUserData} from "@/hooks/useUserData";
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
import {getStoredInviteParams} from "@/utils/invite";
|
import {getStoredInviteParams} from "@/utils/invite";
|
||||||
import UnifiedQRButton from "@/components/UnifiedQRButton";
|
import UnifiedQRButton from "@/components/UnifiedQRButton";
|
||||||
|
import {useThemeStyles} from "@/hooks/useTheme";
|
||||||
|
|
||||||
const UserCard = forwardRef<any, any>((_, ref) => {
|
const UserCard = forwardRef<any, any>((_, ref) => {
|
||||||
const {data, refresh} = useUserData()
|
const {data, refresh} = useUserData()
|
||||||
@@ -17,6 +18,8 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
|||||||
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
||||||
const [userInfo, setUserInfo] = useState<User>()
|
const [userInfo, setUserInfo] = useState<User>()
|
||||||
|
|
||||||
|
const themeStyles = useThemeStyles();
|
||||||
|
|
||||||
// 下拉刷新
|
// 下拉刷新
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
await refresh()
|
await refresh()
|
||||||
@@ -95,7 +98,6 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const openSetting = () => {
|
const openSetting = () => {
|
||||||
// Taro.openSetting:调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。
|
// Taro.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 handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 判断用户是否已登录
|
||||||
|
if(IsLogin){
|
||||||
|
return navTo(`/user/profile/profile`)
|
||||||
|
}
|
||||||
|
|
||||||
// 获取存储的邀请参数
|
// 获取存储的邀请参数
|
||||||
const inviteParams = getStoredInviteParams()
|
const inviteParams = getStoredInviteParams()
|
||||||
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||||
@@ -165,34 +172,19 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className={'header-bg pt-20'}>
|
<View className={'pt-14'}>
|
||||||
<View className={'p-4'}>
|
|
||||||
{/* 使用相对定位容器,让个人资料图片可以绝对定位在右上角 */}
|
{/* 使用相对定位容器,让个人资料图片可以绝对定位在右上角 */}
|
||||||
<View className="relative">
|
<View className="relative z-20">
|
||||||
<View
|
<View
|
||||||
className={'user-card w-full flex flex-col justify-around rounded-xl'}
|
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={'user-card-header flex w-full justify-between items-center pt-4'}>
|
||||||
<View className={'flex items-center mx-4'}>
|
<View className={'flex items-center mx-4'} onClick={handleGetPhoneNumber}>
|
||||||
{
|
<Avatar size="large"
|
||||||
IsLogin ? (
|
src={userInfo?.avatar || ''}
|
||||||
<Avatar size="large"
|
shape="round"/>
|
||||||
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={'user-info flex flex-col px-2'}>
|
<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 ? (
|
{IsLogin ? (
|
||||||
<View className={'grade text-xs py-1'}>
|
<View className={'grade text-xs py-1'}>
|
||||||
<Tag type="success" round>
|
<Tag type="success" round>
|
||||||
@@ -210,7 +202,7 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
|||||||
}}>
|
}}>
|
||||||
{/*统一扫码入口 - 支持登录和核销*/}
|
{/*统一扫码入口 - 支持登录和核销*/}
|
||||||
<UnifiedQRButton
|
<UnifiedQRButton
|
||||||
text="扫码"
|
text="扫一扫"
|
||||||
size="small"
|
size="small"
|
||||||
onSuccess={(result) => {
|
onSuccess={(result) => {
|
||||||
console.log('统一扫码成功:', result);
|
console.log('统一扫码成功:', result);
|
||||||
@@ -229,47 +221,31 @@ const UserCard = forwardRef<any, any>((_, ref) => {
|
|||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</View>
|
</View>
|
||||||
<View className={'flex justify-around mt-1'}>
|
<View className={'py-2'}>
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
<View className={'flex justify-around mt-1'}>
|
||||||
onClick={() => navTo('/user/wallet/wallet', true)}>
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
<Text className={'text-sm text-gray-500'}>余额</Text>
|
onClick={() => navTo('/user/wallet/wallet', true)}>
|
||||||
<Text className={'text-xl'}>{data?.balance || '0.00'}</Text>
|
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>余额</Text>
|
||||||
</View>
|
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.balance || '0.00'}</Text>
|
||||||
<View className={'item flex justify-center flex-col items-center'}>
|
</View>
|
||||||
<Text className={'text-sm text-gray-500'}>积分</Text>
|
<View className={'item flex justify-center flex-col items-center'}>
|
||||||
<Text className={'text-xl'}>{data?.points || 0}</Text>
|
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>积分</Text>
|
||||||
</View>
|
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.points || 0}</Text>
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
</View>
|
||||||
onClick={() => navTo('/user/coupon/index', true)}>
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
<Text className={'text-sm text-gray-500'}>优惠券</Text>
|
onClick={() => navTo('/user/coupon/index', true)}>
|
||||||
<Text className={'text-xl'}>{data?.coupons || 0}</Text>
|
<Text className={'text-xs text-gray-200'} style={themeStyles.textColor}>优惠券</Text>
|
||||||
</View>
|
<Text className={'text-xl text-white'} style={themeStyles.textColor}>{data?.coupons || 0}</Text>
|
||||||
<View className={'item flex justify-center flex-col items-center'}
|
</View>
|
||||||
onClick={() => navTo('/user/gift/index', true)}>
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
<Text className={'text-sm text-gray-500'}>礼品卡</Text>
|
onClick={() => navTo('/user/gift/index', true)}>
|
||||||
<Text className={'text-xl'}>{data?.giftCards || 0}</Text>
|
<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>
|
||||||
</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>
|
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const UserCell = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View className={'px-4'}>
|
<View className={'px-4'} style={{ marginTop: '8px', position: 'relative', zIndex: 20 }}>
|
||||||
|
|
||||||
<Cell.Group divider={true} description={
|
<Cell.Group divider={true} description={
|
||||||
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
|||||||
@@ -138,6 +138,53 @@ const UserCell = () => {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
</View>
|
</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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<View className={'px-4 pb-2'}>
|
<View className={'px-4 pb-2 z-30 relative'} style={{ marginTop: '8px' }}>
|
||||||
<View
|
<View
|
||||||
className={'user-card w-full flex flex-col justify-around rounded-xl shadow-sm'}
|
className={'user-card w-full flex flex-col justify-around rounded-xl shadow-sm'}
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import UserCard from "./components/UserCard";
|
|||||||
import UserOrder from "./components/UserOrder";
|
import UserOrder from "./components/UserOrder";
|
||||||
import UserFooter from "./components/UserFooter";
|
import UserFooter from "./components/UserFooter";
|
||||||
import {useUserData} from "@/hooks/useUserData";
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
|
import {View} from '@tarojs/components';
|
||||||
import './user.scss'
|
import './user.scss'
|
||||||
import IsDealer from "./components/IsDealer";
|
import IsDealer from "./components/IsDealer";
|
||||||
|
import {useThemeStyles} from "@/hooks/useTheme";
|
||||||
import UserGrid from "@/pages/user/components/UserGrid";
|
import UserGrid from "@/pages/user/components/UserGrid";
|
||||||
|
|
||||||
function User() {
|
function User() {
|
||||||
|
|
||||||
const { refresh } = useUserData()
|
const {refresh} = useUserData()
|
||||||
const userCardRef = useRef<any>()
|
const userCardRef = useRef<any>()
|
||||||
|
const themeStyles = useThemeStyles();
|
||||||
|
|
||||||
// 下拉刷新处理
|
// 下拉刷新处理
|
||||||
const handleRefresh = async () => {
|
const handleRefresh = async () => {
|
||||||
@@ -30,15 +33,30 @@ function User() {
|
|||||||
onRefresh={handleRefresh}
|
onRefresh={handleRefresh}
|
||||||
headHeight={60}
|
headHeight={60}
|
||||||
>
|
>
|
||||||
<div className={'w-full'} style={{
|
{/* 装饰性背景 */}
|
||||||
background: 'linear-gradient(to bottom, #e9fff2, #f9fafb)'
|
<View className={'h-64 w-full fixed top-0 z-0'} style={themeStyles.primaryBackground}>
|
||||||
}}>
|
{/* 装饰性背景元素 - 小程序兼容版本 */}
|
||||||
<UserCard ref={userCardRef}/>
|
<View className="absolute w-32 h-32 rounded-full" style={{
|
||||||
<UserOrder/>
|
backgroundColor: 'rgba(255, 255, 255, 0.1)',
|
||||||
<IsDealer/>
|
top: '-16px',
|
||||||
<UserGrid/>
|
right: '-16px'
|
||||||
<UserFooter/>
|
}}></View>
|
||||||
</div>
|
<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>
|
</PullToRefresh>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
102
src/pages/user_bak/components/IsDealer.tsx
Normal file
102
src/pages/user_bak/components/IsDealer.tsx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import {Cell} from '@nutui/nutui-react-taro'
|
||||||
|
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, useState} from "react";
|
||||||
|
import {useDealerUser} from "@/hooks/useDealerUser";
|
||||||
|
import {configWebsiteField} from "@/api/cms/cmsWebsiteField";
|
||||||
|
import {Config} from "@/api/cms/cmsWebsiteField/model";
|
||||||
|
|
||||||
|
const UserCell = () => {
|
||||||
|
const {isSuperAdmin} = useUser();
|
||||||
|
const {dealerUser} = useDealerUser()
|
||||||
|
const [config, setConfig] = useState<Config>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
configWebsiteField().then(data => {
|
||||||
|
console.log(data)
|
||||||
|
setConfig(data)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理中心
|
||||||
|
*/
|
||||||
|
if (isSuperAdmin()) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View className={'px-4'}>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
style={{
|
||||||
|
backgroundImage: 'linear-gradient(to right bottom, #e53e3e, #c53030)',
|
||||||
|
}}
|
||||||
|
title={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<Setting className={'text-white '} size={16}/>
|
||||||
|
<Text style={{fontSize: '16px'}} className={'pl-3 text-white font-medium'}>管理中心</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
extra={<ArrowRight color="#ffffff" size={18}/>}
|
||||||
|
onClick={() => navTo('/admin/index', true)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销中心
|
||||||
|
*/
|
||||||
|
if (dealerUser) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View className={'px-4'}>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
style={{
|
||||||
|
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
||||||
|
}}
|
||||||
|
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>
|
||||||
|
{/*<Text className={'text-white opacity-80 pl-3'}>门店核销</Text>*/}
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => navTo('/dealer/index', true)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 普通用户
|
||||||
|
*/
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View className={'px-4'}>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
style={{
|
||||||
|
backgroundImage: 'linear-gradient(to right bottom, #54a799, #177b73)',
|
||||||
|
}}
|
||||||
|
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'}>{config?.vipText}开通VIP</Text>
|
||||||
|
<Text className={'text-white opacity-80 pl-3'}>{config?.vipComments}享优惠</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => navTo('/dealer/apply/add', true)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default UserCell
|
||||||
277
src/pages/user_bak/components/UserCard.tsx
Normal file
277
src/pages/user_bak/components/UserCard.tsx
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
import {Avatar, Tag, Space, Button} from '@nutui/nutui-react-taro'
|
||||||
|
import {View, Text, Image} from '@tarojs/components'
|
||||||
|
import {getUserInfo, getWxOpenId} from '@/api/layout';
|
||||||
|
import Taro from '@tarojs/taro';
|
||||||
|
import {useEffect, useState, forwardRef, useImperativeHandle} from "react";
|
||||||
|
import {User} from "@/api/system/user/model";
|
||||||
|
import navTo from "@/utils/common";
|
||||||
|
import {TenantId} from "@/config/app";
|
||||||
|
import {useUser} from "@/hooks/useUser";
|
||||||
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
|
import {getStoredInviteParams} from "@/utils/invite";
|
||||||
|
import UnifiedQRButton from "@/components/UnifiedQRButton";
|
||||||
|
|
||||||
|
const UserCard = forwardRef<any, any>((_, ref) => {
|
||||||
|
const {data, refresh} = useUserData()
|
||||||
|
const {getDisplayName, getRoleName} = useUser();
|
||||||
|
const [IsLogin, setIsLogin] = useState<boolean>(false)
|
||||||
|
const [userInfo, setUserInfo] = useState<User>()
|
||||||
|
|
||||||
|
// 下拉刷新
|
||||||
|
const handleRefresh = async () => {
|
||||||
|
await refresh()
|
||||||
|
Taro.showToast({
|
||||||
|
title: '刷新成功',
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
useImperativeHandle(ref, () => ({
|
||||||
|
handleRefresh
|
||||||
|
}))
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||||||
|
Taro.getSetting({
|
||||||
|
success: (res) => {
|
||||||
|
if (res.authSetting['scope.userInfo']) {
|
||||||
|
// 用户已经授权过,可以直接获取用户信息
|
||||||
|
console.log('用户已经授权过,可以直接获取用户信息')
|
||||||
|
reload();
|
||||||
|
} else {
|
||||||
|
// 用户未授权,需要弹出授权窗口
|
||||||
|
console.log('用户未授权,需要弹出授权窗口')
|
||||||
|
showAuthModal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const reload = () => {
|
||||||
|
Taro.getUserInfo({
|
||||||
|
success: (res) => {
|
||||||
|
const avatar = res.userInfo.avatarUrl;
|
||||||
|
setUserInfo({
|
||||||
|
avatar,
|
||||||
|
nickname: res.userInfo.nickName,
|
||||||
|
sexName: res.userInfo.gender == 1 ? '男' : '女'
|
||||||
|
})
|
||||||
|
getUserInfo().then((data) => {
|
||||||
|
if (data) {
|
||||||
|
setUserInfo(data)
|
||||||
|
setIsLogin(true);
|
||||||
|
Taro.setStorageSync('UserId', data.userId)
|
||||||
|
|
||||||
|
// 获取openId
|
||||||
|
if (!data.openid) {
|
||||||
|
Taro.login({
|
||||||
|
success: (res) => {
|
||||||
|
getWxOpenId({code: res.code}).then(() => {
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('未登录')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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']) {
|
||||||
|
// 用户授权成功,可以获取用户信息
|
||||||
|
reload();
|
||||||
|
} else {
|
||||||
|
// 用户拒绝授权,提示授权失败
|
||||||
|
Taro.showToast({
|
||||||
|
title: '授权失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 获取用户手机号 */
|
||||||
|
const handleGetPhoneNumber = ({detail}: { detail: { code?: string, encryptedData?: string, iv?: string } }) => {
|
||||||
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
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: function (res) {
|
||||||
|
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)
|
||||||
|
setUserInfo(res.data.data.user)
|
||||||
|
setIsLogin(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log('登录失败!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className={'header-bg pt-20'}>
|
||||||
|
<View className={'p-4'}>
|
||||||
|
{/* 使用相对定位容器,让个人资料图片可以绝对定位在右上角 */}
|
||||||
|
<View className="relative">
|
||||||
|
<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={'user-info flex flex-col px-2'}>
|
||||||
|
<View className={'py-1 text-black font-bold'}>{getDisplayName()}</View>
|
||||||
|
{IsLogin ? (
|
||||||
|
<View className={'grade text-xs py-1'}>
|
||||||
|
<Tag type="success" round>
|
||||||
|
<Text className={'p-1'}>
|
||||||
|
{getRoleName()}
|
||||||
|
</Text>
|
||||||
|
</Tag>
|
||||||
|
</View>
|
||||||
|
) : ''}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<Space style={{
|
||||||
|
marginTop: '30px',
|
||||||
|
marginRight: '10px'
|
||||||
|
}}>
|
||||||
|
{/*统一扫码入口 - 支持登录和核销*/}
|
||||||
|
<UnifiedQRButton
|
||||||
|
text="扫码"
|
||||||
|
size="small"
|
||||||
|
onSuccess={(result) => {
|
||||||
|
console.log('统一扫码成功:', result);
|
||||||
|
// 根据扫码类型给出不同的提示
|
||||||
|
if (result.type === 'verification') {
|
||||||
|
// 核销成功,可以显示更多信息或跳转到详情页
|
||||||
|
Taro.showModal({
|
||||||
|
title: '核销成功',
|
||||||
|
content: `已成功核销的品类:${result.data.goodsName || '礼品卡'},面值¥${result.data.faceValue}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onError={(error) => {
|
||||||
|
console.error('统一扫码失败:', error);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default UserCard;
|
||||||
144
src/pages/user_bak/components/UserCell.tsx
Normal file
144
src/pages/user_bak/components/UserCell.tsx
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import {Cell} from '@nutui/nutui-react-taro'
|
||||||
|
import navTo from "@/utils/common";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {View, Text} from '@tarojs/components'
|
||||||
|
import {ArrowRight, ShieldCheck, LogisticsError, Location, Tips, Ask} from '@nutui/icons-react-taro'
|
||||||
|
import {useUser} from '@/hooks/useUser'
|
||||||
|
|
||||||
|
const UserCell = () => {
|
||||||
|
const {logoutUser, isCertified} = useUser();
|
||||||
|
|
||||||
|
const onLogout = () => {
|
||||||
|
Taro.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要退出登录吗?',
|
||||||
|
success: function (res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 使用 useUser hook 的 logoutUser 方法
|
||||||
|
logoutUser();
|
||||||
|
Taro.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View className={'px-4'}>
|
||||||
|
|
||||||
|
<Cell.Group divider={true} description={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<Text style={{marginTop: '12px'}}>我的服务</Text>
|
||||||
|
</View>
|
||||||
|
}>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
style={{
|
||||||
|
display: 'none'
|
||||||
|
}}
|
||||||
|
title={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<LogisticsError size={16}/>
|
||||||
|
<Text className={'pl-3 text-sm'}>我的钱包</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => {
|
||||||
|
navTo('/user/wallet/index', true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<Location size={16}/>
|
||||||
|
<Text className={'pl-3 text-sm'}>收货地址</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => {
|
||||||
|
navTo('/user/address/index', true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<ShieldCheck size={16} color={isCertified() ? '#52c41a' : '#666'}/>
|
||||||
|
<Text className={'pl-3 text-sm'}>实名认证</Text>
|
||||||
|
{isCertified() && (
|
||||||
|
<Text className={'pl-2 text-xs text-green-500'}>已认证</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => {
|
||||||
|
navTo('/user/userVerify/index', true)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<Ask size={16}/>
|
||||||
|
<Text className={'pl-3 text-sm'}>常见问题</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => {
|
||||||
|
navTo('/user/help/index')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<Tips size={16}/>
|
||||||
|
<Text className={'pl-3 text-sm'}>关于我们</Text>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => {
|
||||||
|
navTo('/user/about/index')
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Cell.Group>
|
||||||
|
<Cell.Group divider={true} description={
|
||||||
|
<View style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||||
|
<Text style={{marginTop: '12px'}}>账号管理</Text>
|
||||||
|
</View>
|
||||||
|
}>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title="账号安全"
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => navTo('/user/profile/profile', true)}
|
||||||
|
/>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title="切换主题"
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={() => navTo('/user/theme/index', true)}
|
||||||
|
/>
|
||||||
|
<Cell
|
||||||
|
className="nutui-cell-clickable"
|
||||||
|
title="退出登录"
|
||||||
|
align="center"
|
||||||
|
extra={<ArrowRight color="#cccccc" size={18}/>}
|
||||||
|
onClick={onLogout}
|
||||||
|
/>
|
||||||
|
</Cell.Group>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default UserCell
|
||||||
102
src/pages/user_bak/components/UserFooter.tsx
Normal file
102
src/pages/user_bak/components/UserFooter.tsx
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import {loginBySms} from "@/api/passport/login";
|
||||||
|
import {useState} from "react";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {Popup} from '@nutui/nutui-react-taro'
|
||||||
|
import {UserParam} from "@/api/system/user/model";
|
||||||
|
import {Button} from '@nutui/nutui-react-taro'
|
||||||
|
import {Form, Input} from '@nutui/nutui-react-taro'
|
||||||
|
import {Copyright, Version} from "@/config/app";
|
||||||
|
const UserFooter = () => {
|
||||||
|
const [openLoginByPhone, setOpenLoginByPhone] = useState(false)
|
||||||
|
const [clickNum, setClickNum] = useState<number>(0)
|
||||||
|
const [FormData, setFormData] = useState<UserParam>(
|
||||||
|
{
|
||||||
|
phone: undefined,
|
||||||
|
password: undefined
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const onLoginByPhone = () => {
|
||||||
|
setFormData({})
|
||||||
|
setClickNum(clickNum + 1);
|
||||||
|
if (clickNum > 10) {
|
||||||
|
setOpenLoginByPhone(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeLoginByPhone = () => {
|
||||||
|
setClickNum(0)
|
||||||
|
setOpenLoginByPhone(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const submitByPhone = (values: any) => {
|
||||||
|
loginBySms({
|
||||||
|
phone: values.phone,
|
||||||
|
code: values.code
|
||||||
|
}).then(() => {
|
||||||
|
setOpenLoginByPhone(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
Taro.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
},1000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className={'text-center py-4 w-full text-gray-300'} onClick={onLoginByPhone}>
|
||||||
|
<div className={'text-xs text-gray-400 py-1'}>当前版本:{Version}</div>
|
||||||
|
<div className={'text-xs text-gray-400 py-1'}>Copyright © { new Date().getFullYear() } {Copyright}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Popup
|
||||||
|
style={{width: '350px', padding: '10px'}}
|
||||||
|
visible={openLoginByPhone}
|
||||||
|
closeOnOverlayClick={false}
|
||||||
|
closeable={true}
|
||||||
|
onClose={closeLoginByPhone}
|
||||||
|
>
|
||||||
|
<Form
|
||||||
|
style={{width: '350px',padding: '10px'}}
|
||||||
|
divider
|
||||||
|
initialValues={FormData}
|
||||||
|
labelPosition="left"
|
||||||
|
onFinish={(values) => submitByPhone(values)}
|
||||||
|
footer={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
width: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button nativeType="submit" block style={{backgroundColor: '#000000',color: '#ffffff'}}>
|
||||||
|
提交
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label={'手机号码'}
|
||||||
|
name="phone"
|
||||||
|
required
|
||||||
|
rules={[{message: '手机号码'}]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入手机号码" maxLength={11} type="text"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={'短信验证码'}
|
||||||
|
name="code"
|
||||||
|
required
|
||||||
|
rules={[{message: '短信验证码'}]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入短信验证码" maxLength={6} type="text"/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Popup>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default UserFooter
|
||||||
145
src/pages/user_bak/components/UserGrid.tsx
Normal file
145
src/pages/user_bak/components/UserGrid.tsx
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import {Grid, ConfigProvider} from '@nutui/nutui-react-taro'
|
||||||
|
import navTo from "@/utils/common";
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import {View, Button} from '@tarojs/components'
|
||||||
|
import {
|
||||||
|
ShieldCheck,
|
||||||
|
Location,
|
||||||
|
Tips,
|
||||||
|
Ask,
|
||||||
|
// Dongdong,
|
||||||
|
People,
|
||||||
|
// AfterSaleService,
|
||||||
|
Logout,
|
||||||
|
ShoppingAdd,
|
||||||
|
Service
|
||||||
|
} from '@nutui/icons-react-taro'
|
||||||
|
import {useUser} from "@/hooks/useUser";
|
||||||
|
|
||||||
|
const UserCell = () => {
|
||||||
|
const {logoutUser} = useUser();
|
||||||
|
|
||||||
|
const onLogout = () => {
|
||||||
|
Taro.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定要退出登录吗?',
|
||||||
|
success: function (res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 使用 useUser hook 的 logoutUser 方法
|
||||||
|
logoutUser();
|
||||||
|
Taro.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<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/poster/poster', 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="联系我们">
|
||||||
|
<Button
|
||||||
|
open-type="contact"
|
||||||
|
className="w-full h-full flex flex-col items-center justify-center p-0 bg-transparent"
|
||||||
|
hover-class="none"
|
||||||
|
style={{border: 'none'}}
|
||||||
|
>
|
||||||
|
<View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||||
|
<Service color="#67C23A" size="20"/>
|
||||||
|
</View>
|
||||||
|
</Button>
|
||||||
|
</Grid.Item>
|
||||||
|
|
||||||
|
<Grid.Item text="收货地址" onClick={() => navTo('/user/address/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/userVerify/index', true)}>
|
||||||
|
<View className="text-center">
|
||||||
|
<View className="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||||
|
<ShieldCheck color="#10b981" size="20"/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Grid.Item>
|
||||||
|
|
||||||
|
<Grid.Item text={'推广邀请'} onClick={() => navTo('/dealer/team/index', true)}>
|
||||||
|
<View className="text-center">
|
||||||
|
<View className="w-12 h-12 bg-purple-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||||
|
<People color="#8b5cf6" size="20"/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Grid.Item>
|
||||||
|
|
||||||
|
{/*<Grid.Item text={'我的邀请码'} onClick={() => navTo('/dealer/qrcode/index', true)}>*/}
|
||||||
|
{/* <View className="text-center">*/}
|
||||||
|
{/* <View className="w-12 h-12 bg-orange-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
||||||
|
{/* <Dongdong color="#f59e0b" size="20"/>*/}
|
||||||
|
{/* </View>*/}
|
||||||
|
{/* </View>*/}
|
||||||
|
{/*</Grid.Item>*/}
|
||||||
|
|
||||||
|
{/*<Grid.Item text={'管理中心'} onClick={() => navTo('/admin/index', true)}>*/}
|
||||||
|
{/* <View className="text-center">*/}
|
||||||
|
{/* <View className="w-12 h-12 bg-red-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
|
||||||
|
{/* <AfterSaleService className={'text-red-500'} size="20"/>*/}
|
||||||
|
{/* </View>*/}
|
||||||
|
{/* </View>*/}
|
||||||
|
{/*</Grid.Item>*/}
|
||||||
|
|
||||||
|
<Grid.Item text={'常见问题'} onClick={() => navTo('/user/help/index')}>
|
||||||
|
<View className="text-center">
|
||||||
|
<View className="w-12 h-12 bg-cyan-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||||
|
<Ask className={'text-cyan-500'} 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>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default UserCell
|
||||||
|
|
||||||
122
src/pages/user_bak/components/UserOrder.tsx
Normal file
122
src/pages/user_bak/components/UserOrder.tsx
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import navTo from "@/utils/common";
|
||||||
|
import {View, Text} from '@tarojs/components';
|
||||||
|
import {Badge} from '@nutui/nutui-react-taro';
|
||||||
|
import {ArrowRight, Wallet, Comment, Transit, Refund, Package} from '@nutui/icons-react-taro';
|
||||||
|
import {useOrderStats} from "@/hooks/useOrderStats";
|
||||||
|
|
||||||
|
function UserOrder() {
|
||||||
|
const { orderStats, refreshOrderStats } = useOrderStats();
|
||||||
|
|
||||||
|
// 处理长按刷新
|
||||||
|
const handleLongPress = () => {
|
||||||
|
refreshOrderStats();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View className={'px-4 pb-2'}>
|
||||||
|
<View
|
||||||
|
className={'user-card w-full flex flex-col justify-around rounded-xl shadow-sm'}
|
||||||
|
style={{
|
||||||
|
background: 'linear-gradient(to bottom, #ffffff, #ffffff)', // 这种情况建议使用类名来控制样式(引入外联样式)
|
||||||
|
// margin: '10px auto 0px auto',
|
||||||
|
height: '120px',
|
||||||
|
// paddingBottom: '3px'
|
||||||
|
// borderRadius: '22px 22px 0 0',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View className={'title-bar flex justify-between pt-2'}>
|
||||||
|
<Text className={'title font-medium px-4'}>我的订单</Text>
|
||||||
|
<View
|
||||||
|
className={'more flex items-center px-2'}
|
||||||
|
onClick={() => navTo('/user/order/order', true)}
|
||||||
|
onLongPress={handleLongPress}
|
||||||
|
>
|
||||||
|
<Text className={'text-xs text-gray-500'}>全部订单</Text>
|
||||||
|
<ArrowRight color="#cccccc" size={12}/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={'flex justify-around pb-1 mt-4'}>
|
||||||
|
{/* 待付款 */}
|
||||||
|
{orderStats.pending > 0 ? (
|
||||||
|
<Badge value={orderStats.pending} max={99} fill={'outline'}>
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}>
|
||||||
|
<Wallet size={26} className={'font-normal text-gray-500'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=0', true)}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>待付款</Text>
|
||||||
|
</View>
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=0', true)}>
|
||||||
|
<Wallet size={26} className={'font-normal text-gray-500'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>待付款</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 待发货 */}
|
||||||
|
{orderStats.paid > 0 ? (
|
||||||
|
<Badge value={orderStats.paid} max={99} fill={'outline'}>
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=1', true)}>
|
||||||
|
<Package size={26} className={'text-gray-500 font-normal'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>待发货</Text>
|
||||||
|
</View>
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=1', true)}>
|
||||||
|
<Package size={26} className={'text-gray-500 font-normal'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>待发货</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 待收货 */}
|
||||||
|
{orderStats.shipped > 0 ? (
|
||||||
|
<Badge value={orderStats.shipped} max={99} fill={'outline'}>
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=3', true)}>
|
||||||
|
<Transit size={24} className={'text-gray-500 font-normal'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>待收货</Text>
|
||||||
|
</View>
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=3', true)}>
|
||||||
|
<Transit size={24} className={'text-gray-500 font-normal'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>待收货</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* 已完成 - 不显示badge */}
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=5', true)}>
|
||||||
|
<Comment size={24} className={'text-gray-500 font-normal'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>已完成</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 退货/售后 */}
|
||||||
|
{orderStats.refund > 0 ? (
|
||||||
|
<Badge value={orderStats.refund} max={99} fill={'outline'}>
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=6', true)}>
|
||||||
|
<Refund size={26} className={'font-normal text-gray-500'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>退货/售后</Text>
|
||||||
|
</View>
|
||||||
|
</Badge>
|
||||||
|
) : (
|
||||||
|
<View className={'item flex justify-center flex-col items-center'}
|
||||||
|
onClick={() => navTo('/user/order/order?statusFilter=6', true)}>
|
||||||
|
<Refund size={26} className={'font-normal text-gray-500'}/>
|
||||||
|
<Text className={'text-sm text-gray-600 py-1'}>退货/售后</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserOrder;
|
||||||
5
src/pages/user_bak/user.config.ts
Normal file
5
src/pages/user_bak/user.config.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export default definePageConfig({
|
||||||
|
navigationBarTitleText: '我的',
|
||||||
|
navigationStyle: 'custom',
|
||||||
|
navigationBarBackgroundColor: '#e9fff2'
|
||||||
|
})
|
||||||
9
src/pages/user_bak/user.scss
Normal file
9
src/pages/user_bak/user.scss
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
.header-bg{
|
||||||
|
//background: url('https://oss.wsdns.cn/20250621/edb5d4da976b4d97ba185cb7077d2858.jpg') no-repeat top center;
|
||||||
|
background: linear-gradient(to bottom, #03605c, #18ae4f);
|
||||||
|
background-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-bg{
|
||||||
|
background: url('https://oss.wsdns.cn/20250913/5ae575a50dbb4ccaab086c3679c5e2c3.png') no-repeat top center;
|
||||||
|
}
|
||||||
46
src/pages/user_bak/user.tsx
Normal file
46
src/pages/user_bak/user.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import {useEffect, useRef} from 'react'
|
||||||
|
import {PullToRefresh} from '@nutui/nutui-react-taro'
|
||||||
|
import UserCard from "./components/UserCard";
|
||||||
|
import UserOrder from "./components/UserOrder";
|
||||||
|
import UserFooter from "./components/UserFooter";
|
||||||
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
|
import './user.scss'
|
||||||
|
import IsDealer from "./components/IsDealer";
|
||||||
|
import UserGrid from "@/pages/user/components/UserGrid";
|
||||||
|
|
||||||
|
function User() {
|
||||||
|
|
||||||
|
const { refresh } = useUserData()
|
||||||
|
const userCardRef = useRef<any>()
|
||||||
|
|
||||||
|
// 下拉刷新处理
|
||||||
|
const handleRefresh = async () => {
|
||||||
|
await refresh()
|
||||||
|
// 如果 UserCard 组件有自己的刷新方法,也可以调用
|
||||||
|
if (userCardRef.current?.handleRefresh) {
|
||||||
|
await userCardRef.current.handleRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PullToRefresh
|
||||||
|
onRefresh={handleRefresh}
|
||||||
|
headHeight={60}
|
||||||
|
>
|
||||||
|
<div className={'w-full'} style={{
|
||||||
|
background: 'linear-gradient(to bottom, #e9fff2, #f9fafb)'
|
||||||
|
}}>
|
||||||
|
<UserCard ref={userCardRef}/>
|
||||||
|
<UserOrder/>
|
||||||
|
<IsDealer/>
|
||||||
|
<UserGrid/>
|
||||||
|
<UserFooter/>
|
||||||
|
</div>
|
||||||
|
</PullToRefresh>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default User
|
||||||
@@ -40,9 +40,9 @@ export const gradientThemes: GradientTheme[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'nature',
|
name: 'nature',
|
||||||
primary: '#43e97b',
|
primary: '#03605c',
|
||||||
secondary: '#38f9d7',
|
secondary: '#18ae4f',
|
||||||
background: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)',
|
background: 'linear-gradient(135deg, #03605c 0%, #18ae4f 100%)',
|
||||||
textColor: '#ffffff',
|
textColor: '#ffffff',
|
||||||
description: '自然绿青 - 生机与成长'
|
description: '自然绿青 - 生机与成长'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ module.exports = {
|
|||||||
divideStyle: false,
|
divideStyle: false,
|
||||||
divideOpacity: false,
|
divideOpacity: false,
|
||||||
// 新增禁用项,解决微信小程序兼容性问题
|
// 新增禁用项,解决微信小程序兼容性问题
|
||||||
gap: false, // 禁用 gap 类,因为微信小程序不支持 gap 属性
|
gap: true, // 禁用 gap 类,因为微信小程序不支持 gap 属性
|
||||||
lineClamp: false, // 禁用 line-clamp 类,微信小程序不支持
|
lineClamp: false, // 禁用 line-clamp 类,微信小程序不支持
|
||||||
textIndent: false, // 禁用 text-indent
|
textIndent: false, // 禁用 text-indent
|
||||||
writingMode: false, // 禁用 writing-mode
|
writingMode: false, // 禁用 writing-mode
|
||||||
|
|||||||
Reference in New Issue
Block a user