feat(coupon): 添加优惠券领取中心功能

- 新增优惠券领取中心页面,包含热门优惠券轮播、优惠券列表、筛选功能等
- 实现优惠券数据加载、搜索、下拉刷新、加载更多等功能
- 添加优惠券领取逻辑,支持用户领取优惠券
- 优化邀请小程序码生成和分享功能
-调整首页和用户订单组件的样式
This commit is contained in:
2025-08-22 11:46:12 +08:00
parent 40e282cf8f
commit 46761bdacd
14 changed files with 695 additions and 162 deletions

View File

@@ -15,7 +15,7 @@ import {
const AddUserAddress = () => {
const {user} = useUser()
const [loading, setLoading] = useState<boolean>(true)
const [FormData, setFormData] = useState<ShopDealerApply>({})
const [FormData, setFormData] = useState<ShopDealerApply>()
const formRef = useRef<any>(null)
const [isEditMode, setIsEditMode] = useState<boolean>(false)
const [existingApply, setExistingApply] = useState<ShopDealerApply | null>(null)
@@ -47,16 +47,17 @@ const AddUserAddress = () => {
setExistingApply(res.list[0]);
// 如果有记录,填充表单数据
setFormData(res.list[0]);
setLoading(false)
} else {
setFormData({})
setIsEditMode(false);
setExistingApply(null);
setLoading(false)
}
} catch (error) {
setLoading(true)
console.error('查询申请记录失败:', error);
setIsEditMode(false);
setExistingApply(null);
setFormData({})
}
}
@@ -122,7 +123,11 @@ const AddUserAddress = () => {
if (loading) {
return <Loading className={'px-2'}></Loading>
}
console.log(FormData,'FromData')
if(!FormData){
return <Loading className={'px-2'}></Loading>
}
return (
<>
<Form
@@ -153,29 +158,29 @@ const AddUserAddress = () => {
title={'审核状态'}
extra={
<span style={{
color: FormData.applyStatus === 20 ? '#52c41a' :
FormData.applyStatus === 30 ? '#ff4d4f' : '#faad14'
color: FormData?.applyStatus === 20 ? '#52c41a' :
FormData?.applyStatus === 30 ? '#ff4d4f' : '#faad14'
}}>
{getApplyStatusText(FormData.applyStatus)}
{getApplyStatusText(FormData?.applyStatus)}
</span>
}
/>
{FormData.applyStatus === 20 && (
<Cell title={'审核时间'} extra={FormData.auditTime || '无'}/>
{FormData?.applyStatus === 20 && (
<Cell title={'审核时间'} extra={FormData?.auditTime || '无'}/>
)}
{FormData.applyStatus === 30 && (
<Cell title={'驳回原因'} extra={FormData.rejectReason || '无'}/>
{FormData?.applyStatus === 30 && (
<Cell title={'驳回原因'} extra={FormData?.rejectReason || '无'}/>
)}
</CellGroup>
)}
{/* 底部浮动按钮 */}
{(!isEditMode || FormData.applyStatus === 10 || FormData.applyStatus === 30) && (
{(!isEditMode || FormData?.applyStatus === 10 || FormData?.applyStatus === 30) && (
<FixedButton
icon={<Edit/>}
text={isEditMode ? '保存修改' : '提交申请'}
disabled={FormData.applyStatus === 10}
disabled={FormData?.applyStatus === 10}
onClick={handleFixedButtonClick}
/>
)}

View File

@@ -7,8 +7,7 @@ import {
Dongdong,
ArrowRight,
Purse,
People,
Presentation
People
} from '@nutui/icons-react-taro'
import {useDealerUser} from '@/hooks/useDealerUser'
import { useThemeStyles } from '@/hooks/useTheme'
@@ -244,45 +243,45 @@ const DealerIndex: React.FC = () => {
</Grid>
{/* 第二行功能 */}
<Grid
columns={4}
className="no-border-grid mt-4"
style={{
'--nutui-grid-border-color': 'transparent',
'--nutui-grid-item-border-width': '0px',
border: 'none'
} as React.CSSProperties}
>
<Grid.Item text={'邀请统计'} onClick={() => navigateToPage('/dealer/invite-stats/index')}>
<View className="text-center">
<View className="w-12 h-12 bg-indigo-50 rounded-xl flex items-center justify-center mx-auto mb-2">
<Presentation color="#6366f1" size="20"/>
</View>
</View>
</Grid.Item>
{/*<Grid*/}
{/* columns={4}*/}
{/* className="no-border-grid mt-4"*/}
{/* style={{*/}
{/* '--nutui-grid-border-color': 'transparent',*/}
{/* '--nutui-grid-item-border-width': '0px',*/}
{/* border: 'none'*/}
{/* } as React.CSSProperties}*/}
{/*>*/}
{/* <Grid.Item text={'邀请统计'} onClick={() => navigateToPage('/dealer/invite-stats/index')}>*/}
{/* <View className="text-center">*/}
{/* <View className="w-12 h-12 bg-indigo-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
{/* <Presentation color="#6366f1" size="20"/>*/}
{/* </View>*/}
{/* </View>*/}
{/* </Grid.Item>*/}
{/* 预留其他功能位置 */}
<Grid.Item text={''}>
<View className="text-center">
<View className="w-12 h-12 bg-gray-50 rounded-xl flex items-center justify-center mx-auto mb-2">
</View>
</View>
</Grid.Item>
{/* /!* 预留其他功能位置 *!/*/}
{/* <Grid.Item text={''}>*/}
{/* <View className="text-center">*/}
{/* <View className="w-12 h-12 bg-gray-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
{/* </View>*/}
{/* </View>*/}
{/* </Grid.Item>*/}
<Grid.Item text={''}>
<View className="text-center">
<View className="w-12 h-12 bg-gray-50 rounded-xl flex items-center justify-center mx-auto mb-2">
</View>
</View>
</Grid.Item>
{/* <Grid.Item text={''}>*/}
{/* <View className="text-center">*/}
{/* <View className="w-12 h-12 bg-gray-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
{/* </View>*/}
{/* </View>*/}
{/* </Grid.Item>*/}
<Grid.Item text={''}>
<View className="text-center">
<View className="w-12 h-12 bg-gray-50 rounded-xl flex items-center justify-center mx-auto mb-2">
</View>
</View>
</Grid.Item>
</Grid>
{/* <Grid.Item text={''}>*/}
{/* <View className="text-center">*/}
{/* <View className="w-12 h-12 bg-gray-50 rounded-xl flex items-center justify-center mx-auto mb-2">*/}
{/* </View>*/}
{/* </View>*/}
{/* </Grid.Item>*/}
{/*</Grid>*/}
</ConfigProvider>
</View>
</View>

View File

@@ -1,19 +1,19 @@
import React, { useState, useEffect } from 'react'
import { View, Text, Image } from '@tarojs/components'
import { Button, Loading } from '@nutui/nutui-react-taro'
import { Share, Download, Copy, QrCode } from '@nutui/icons-react-taro'
import React, {useState, useEffect} from 'react'
import {View, Text, Image} from '@tarojs/components'
import {Button, Loading} from '@nutui/nutui-react-taro'
import {Share, Download, Copy, QrCode} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro'
import { useDealerUser } from '@/hooks/useDealerUser'
import { generateInviteCode, getInviteStats } from '@/api/invite'
import type { InviteStats } from '@/api/invite'
import { businessGradients } from '@/styles/gradients'
import {useDealerUser} from '@/hooks/useDealerUser'
import {generateInviteCode, getInviteStats} from '@/api/invite'
import type {InviteStats} from '@/api/invite'
import {businessGradients} from '@/styles/gradients'
const DealerQrcode: React.FC = () => {
const [miniProgramCodeUrl, setMiniProgramCodeUrl] = useState<string>('')
const [loading, setLoading] = useState<boolean>(false)
const [inviteStats, setInviteStats] = useState<InviteStats | null>(null)
const [statsLoading, setStatsLoading] = useState<boolean>(false)
const { dealerUser } = useDealerUser()
const {dealerUser} = useDealerUser()
// 生成小程序码
const generateMiniProgramCode = async () => {
@@ -23,8 +23,8 @@ const DealerQrcode: React.FC = () => {
setLoading(true)
// 生成邀请小程序码
const codeUrl = await generateInviteCode(dealerUser.userId, 'qrcode')
const codeUrl = await generateInviteCode(dealerUser.userId)
console.log('小程序码生成成功:', codeUrl)
if (codeUrl) {
setMiniProgramCodeUrl(codeUrl)
}
@@ -160,7 +160,7 @@ const DealerQrcode: React.FC = () => {
if (!dealerUser) {
return (
<View className="bg-gray-50 min-h-screen flex items-center justify-center">
<Loading />
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
)
@@ -179,7 +179,7 @@ const DealerQrcode: React.FC = () => {
right: '-16px'
}}></View>
<View className="relative z-10">
<View className="relative z-10 flex flex-col">
<Text className="text-2xl font-bold mb-2 text-white"></Text>
<Text className="text-white text-opacity-80">
@@ -189,11 +189,16 @@ const DealerQrcode: React.FC = () => {
<View className="px-4">
{/* 小程序码展示区 */}
{/*<Image*/}
{/* src={'http://127.0.0.1:9200/api/wx-login/getOrderQRCodeUnlimited/33103'}*/}
{/* className="w-full h-full"*/}
{/* mode="aspectFit"*/}
{/*/>*/}
<View className="bg-white rounded-2xl p-6 mb-6 shadow-sm">
<View className="text-center">
{loading ? (
<View className="w-48 h-48 mx-auto mb-4 flex items-center justify-center bg-gray-50 rounded-xl">
<Loading />
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
) : miniProgramCodeUrl ? (
@@ -219,48 +224,52 @@ const DealerQrcode: React.FC = () => {
</View>
)}
<Text className="text-lg font-semibold text-gray-800 mb-2">
<View className="text-lg font-semibold text-gray-800 mb-2">
</Text>
<Text className="text-sm text-gray-500 mb-6">
</View>
<View className="text-sm text-gray-500 mb-6">
</Text>
</View>
</View>
</View>
{/* 操作按钮 */}
<View className="space-y-3">
<Button
type="primary"
size="large"
block
icon={<Download />}
onClick={saveMiniProgramCode}
disabled={!miniProgramCodeUrl || loading}
>
</Button>
<Button
size="large"
block
icon={<Copy />}
onClick={copyInviteInfo}
disabled={!dealerUser?.userId || loading}
>
</Button>
<Button
size="large"
block
fill="outline"
icon={<Share />}
onClick={shareMiniProgramCode}
disabled={!dealerUser?.userId || loading}
>
</Button>
<View className={'gap-2'}>
<View className={'my-2'}>
<Button
type="primary"
size="large"
block
icon={<Download/>}
onClick={saveMiniProgramCode}
disabled={!miniProgramCodeUrl || loading}
>
</Button>
</View>
<View className={'my-2 bg-white'}>
<Button
size="large"
block
icon={<Copy/>}
onClick={copyInviteInfo}
disabled={!dealerUser?.userId || loading}
>
</Button>
</View>
<View className={'my-2 bg-white'}>
<Button
size="large"
block
fill="outline"
icon={<Share/>}
onClick={shareMiniProgramCode}
disabled={!dealerUser?.userId || loading}
>
</Button>
</View>
</View>
{/* 推广说明 */}
@@ -293,7 +302,7 @@ const DealerQrcode: React.FC = () => {
<Text className="font-semibold text-gray-800 mb-3"></Text>
{statsLoading ? (
<View className="flex items-center justify-center py-8">
<Loading />
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
) : inviteStats ? (
@@ -353,7 +362,7 @@ const DealerQrcode: React.FC = () => {
</View>
) : (
<View className="text-center py-8">
<Text className="text-gray-500"></Text>
<View className="text-gray-500"></View>
<Button
size="small"
type="primary"