import React, { useState, useEffect } from 'react' import { View, Text, Input, ScrollView } from '@tarojs/components' import Taro from '@tarojs/taro' import { useUser } from '@/hooks/useUser' import { useRequest } from '@/hooks/useRequest' import { useScrollHeight } from '@/hooks/useScrollHeight' import { useRechargeCode, pageRechargeCodeRecords } from '@/api/shop/shopRechargeCode' import type { ShopRechargeCode } from '@/api/shop/shopRechargeCode/model' import { getUserBalance } from '@/api/system/user' definePageConfig({ navigationBarTitleText: '兑换码充值', }) const RedeemPage: React.FC = () => { const { isLoggedIn } = useUser() const maxPopupHeight = useScrollHeight(0) // 兑换码输入 const [code, setCode] = useState('') const [submitting, setSubmitting] = useState(false) const [redeemSuccess, setRedeemSuccess] = useState(false) const [redeemAmount, setRedeemAmount] = useState('') // 兑换记录 const [records, setRecords] = useState([]) const [loadingRecords, setLoadingRecords] = useState(false) const [page, setPage] = useState(1) const [hasMore, setHasMore] = useState(true) const [loadingMore, setLoadingMore] = useState(false) // 兑换请求 const { run: runUseCode } = useRequest(useRechargeCode, { manual: true }) // 加载兑换记录 const loadRecords = async (isLoadMore = false) => { if (isLoadMore) { if (loadingMore || !hasMore) return setLoadingMore(true) } else { setLoadingRecords(true) setPage(1) } try { const res = await pageRechargeCodeRecords({ page: isLoadMore ? page + 1 : 1, limit: 10 }) const newRecords = res?.records || [] if (isLoadMore) { setRecords(prev => [...prev, ...newRecords]) setPage(prev => prev + 1) } else { setRecords(newRecords) } setHasMore(newRecords.length >= 10) } catch (err) { console.error('加载兑换记录失败', err) } finally { setLoadingRecords(false) setLoadingMore(false) } } // 初始化加载 useEffect(() => { if (isLoggedIn) { loadRecords() } }, [isLoggedIn]) // 兑换 const handleRedeem = async () => { const trimCode = code.trim().toUpperCase() if (!trimCode) { Taro.showToast({ title: '请输入兑换码', icon: 'none' }) return } setSubmitting(true) try { const res = await runUseCode(trimCode) setRedeemSuccess(true) setRedeemAmount(res?.amount || '0') Taro.showToast({ title: '兑换成功', icon: 'success' }) // 刷新余额(通过事件通知) const pages = Taro.getCurrentPages() const userPage = pages.find(p => p.route === 'pages/user/wallet') if (userPage) { userPage.onShow() } // 刷新记录 await loadRecords() } catch (err: any) { Taro.showToast({ title: err.message || '兑换失败,兑换码无效或已过期', icon: 'none' }) } finally { setSubmitting(false) } } // 重置表单 const resetForm = () => { setCode('') setRedeemSuccess(false) setRedeemAmount('') } // 复制兑换码 const copyCode = (codeStr: string) => { Taro.setClipboardData({ data: codeStr, success: () => { Taro.showToast({ title: '已复制', icon: 'success' }) } }) } // 滚动到底部加载更多 const handleScrollToLower = () => { if (hasMore && !loadingMore) { loadRecords(true) } } // 状态文本 const getStatusText = (status: number) => { const map: Record = { 0: '未使用', 1: '已使用', 2: '已过期' } return map[status] || '未知' } // 状态颜色 const getStatusColor = (status: number) => { const map: Record = { 0: 'text-blue-500', 1: 'text-green-500', 2: 'text-gray-400' } return map[status] || 'text-gray-400' } return ( {/* 兑换说明卡片 */} 🎫 兑换说明 请输入管理员提供的兑换码,每个兑换码只能使用一次,兑换成功后余额将自动到账。 {/* 兑换表单 */} {!redeemSuccess ? ( 兑换码充值 setCode(e.detail.value)} maxlength={32} /> {submitting ? '兑换中...' : '立即兑换'} ) : ( /* 兑换成功结果 */ 🎉 兑换成功! 已成功充值 ¥{redeemAmount},余额已到账 继续兑换 Taro.navigateTo({ url: '/pages/user/wallet' })} > 查看余额 )} {/* 兑换记录 */} 兑换记录 loadRecords()} > 刷新 🔄 {loadingRecords ? ( 加载中... ) : records.length === 0 ? ( 📋 暂无兑换记录 ) : ( {records.map((record, idx) => ( {getStatusText(record.status)} {record.status === 1 && ( +¥{Number(record.amount).toFixed(2)} )} copyCode(record.code)} > 码: {record.code} 📋 {record.usedAt || record.createTime} {record.status === 1 && ( +¥{Number(record.amount).toFixed(2)} )} ))} {loadingMore && ( 加载更多... )} {!hasMore && records.length > 0 && ( 没有更多了 )} )} ) } export default RedeemPage