Files
mp-10550/src/user/gift/redeem.tsx
赵忠林 06a3b15842 refactor(api): 更新 API调用以使用新的请求工具- 将所有 API 调用中的 request-legacy 替换为 request
- 优化部分 API 调用的参数传递方式
- 统一导入 ApiResult 和 PageResult 类型的路径
2025-08-18 20:39:31 +08:00

279 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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

import {useState, useEffect} from "react";
import {useRouter} from '@tarojs/taro'
import {Button, ConfigProvider, Input, Divider} from '@nutui/nutui-react-taro'
import {ArrowLeft, QrCode, Gift, Voucher} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro'
import {View, Text} from '@tarojs/components'
import dayjs from 'dayjs'
import {ShopGift} from "@/api/shop/shopGift/model";
import {pageShopGift, updateShopGift} from "@/api/shop/shopGift";
import GiftCard from "@/components/GiftCard";
const GiftCardRedeem = () => {
const router = useRouter()
const [code, setCode] = useState('')
const [loading, setLoading] = useState(false)
const [validating, setValidating] = useState(false)
const [validGift, setValidGift] = useState<ShopGift | null>(null)
const [redeemSuccess, setRedeemSuccess] = useState(false)
// 从路由参数获取扫码结果
useEffect(() => {
if (router.params.code) {
const scannedCode = decodeURIComponent(router.params.code)
setCode(scannedCode)
handleValidateCode(scannedCode)
}
}, [router.params.code])
// 验证兑换码
const handleValidateCode = async (inputCode?: string) => {
const codeToValidate = inputCode || code
if (!codeToValidate.trim()) {
Taro.showToast({
title: '请输入兑换码',
icon: 'none'
})
return
}
setValidating(true)
try {
const gifts = await pageShopGift({code: codeToValidate,status: 0})
if(gifts?.count == 0){
Taro.showToast({
title: '兑换码无效或已使用',
icon: 'none'
})
return
}
const item = gifts?.list[0];
if(item){
setValidGift(item)
Taro.showToast({
title: '验证成功',
icon: 'success'
})
}
} catch (error) {
console.error('验证兑换码失败:', error)
setValidGift(null)
Taro.showToast({
title: '兑换码无效或已使用',
icon: 'error'
})
} finally {
setValidating(false)
}
}
// 兑换礼品卡
const handleRedeem = async () => {
if (!validGift || !code.trim()) return
setLoading(true)
try {
await updateShopGift({
...validGift,
userId: Taro.getStorageSync('UserId'),
takeTime: dayjs.unix(Date.now() / 1000).format('YYYY-MM-DD HH:mm:ss')
})
setRedeemSuccess(true)
Taro.showToast({
title: '兑换成功',
icon: 'success'
})
} catch (error) {
console.error('兑换礼品卡失败:', error)
Taro.showToast({
title: '兑换失败',
icon: 'error'
})
} finally {
setLoading(false)
}
}
// 扫码兑换
const handleScanCode = () => {
Taro.scanCode({
success: (res) => {
const scannedCode = res.result
if (scannedCode) {
setCode(scannedCode)
handleValidateCode(scannedCode)
}
},
fail: () => {
Taro.showToast({
title: '扫码失败',
icon: 'error'
})
}
})
}
// 返回上一页
const handleBack = () => {
Taro.navigateBack()
}
// 查看我的礼品卡
const handleViewMyGifts = () => {
Taro.navigateTo({
url: '/user/gift/index'
})
}
// 转换礼品卡数据
const transformGiftData = (gift: ShopGift) => {
return {
id: gift.id || 0,
name: gift.name || '礼品卡',
description: gift.description,
code: gift.code,
goodsImage: gift.goodsImage,
faceValue: gift.faceValue,
type: gift.type,
expireTime: gift.expireTime,
takeTime: gift.takeTime,
useLocation: gift.useLocation,
contactInfo: gift.contactInfo,
showCode: false, // 兑换页面不显示兑换码
showUseBtn: false, // 兑换页面不显示使用按钮
showDetailBtn: false, // 兑换页面不显示详情按钮
theme: 'gold' as const
}
}
return (
<ConfigProvider>
{/* 自定义导航栏 */}
<View className="flex items-center justify-between p-4 bg-white border-b border-gray-100 hidden">
<View className="flex items-center" onClick={handleBack}>
<ArrowLeft size="20" />
<Text className="ml-2 text-lg"></Text>
</View>
</View>
{!redeemSuccess ? (
<>
{/* 兑换说明 */}
<View className="bg-blue-50 mx-4 mt-4 p-4 rounded-xl border border-blue-200">
<View className="flex items-center mb-2">
<Gift size="20" className="text-blue-600 mr-2" />
<Text className="font-semibold text-blue-800"></Text>
</View>
<Text className="text-blue-700 text-sm leading-relaxed">
使
</Text>
</View>
{/* 兑换码输入 */}
<View className="bg-white mx-4 mt-4 p-4 rounded-xl">
<Text className="font-semibold mb-3 text-gray-800"></Text>
<View className="mb-4">
<Input
placeholder="请输入礼品卡兑换码"
value={code}
onChange={setCode}
clearable
className="border border-gray-200 rounded-lg"
/>
</View>
<View className="flex gap-3">
<Button
fill="outline"
size="large"
className="flex-1"
icon={<QrCode />}
onClick={handleScanCode}
>
</Button>
<Button
type="primary"
size="large"
className="flex-1"
loading={validating}
onClick={() => handleValidateCode()}
>
</Button>
</View>
</View>
{/* 验证结果 */}
{validGift && (
<>
<Divider className="my-4"></Divider>
<View className="mx-4">
<GiftCard {...transformGiftData(validGift)} />
</View>
<View className="mx-4 mt-4">
<Button
type="primary"
size="large"
block
loading={loading}
onClick={handleRedeem}
>
</Button>
</View>
</>
)}
</>
) : (
/* 兑换成功页面 */
<View className="flex flex-col items-center justify-center px-4" style={{height: '600px'}}>
<View className="text-center">
<View className="w-20 h-20 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
<Voucher size="40" className="text-green-600" />
</View>
<Text className="text-2xl font-bold text-gray-900 mb-2"></Text>
<Text className="text-left text-gray-500 mb-6"></Text>
{validGift && (
<View className="mb-6">
<GiftCard {...transformGiftData(validGift)} />
</View>
)}
<View className="flex flex-col gap-3 w-full max-w-xs">
<Button
type="primary"
size="large"
block
onClick={handleViewMyGifts}
>
</Button>
<Button
fill="outline"
size="large"
block
onClick={() => {
setCode('')
setValidGift(null)
setRedeemSuccess(false)
}}
>
</Button>
</View>
</View>
</View>
)}
</ConfigProvider>
);
};
export default GiftCardRedeem;