Files
template-10579/src/user/gift/detail.tsx
赵忠林 eee4644d06 ```
feat(registration): 优化经销商注册流程并增加地址定位功能

- 修改导航栏标题从“邀请注册”为“注册成为会员”
- 修复重复提交问题并移除不必要的submitting状态
- 增加昵称和头像的必填验证提示
- 添加用户角色缺失时的默认角色写入机制
- 集成地图选点功能,支持经纬度获取和地址解析
- 实现微信地址导入功能,自动填充基本信息
- 增加定位权限检查和错误处理机制
- 添加.gitignore规则忽略备份文件夹src__bak
- 移除已废弃的银行卡和客户管理页面代码
- 优化表单验证规则和错误提示信息
- 实现经销商注册成功后自动跳转到“我的”页面
- 添加用户信息缓存刷新机制确保角色信息同步
```
2026-03-01 12:35:41 +08:00

336 lines
9.6 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, Divider} from '@nutui/nutui-react-taro'
import {Gift, Clock, Location, Phone, Copy, QrCode} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro'
import {View, Text} from '@tarojs/components'
import {ShopGift} from "@/api/shop/shopGift/model";
import {getShopGift} from "@/api/shop/shopGift";
import GiftCardShare from "@/components/GiftCardShare";
import SimpleQRCodeModal from "@/components/SimpleQRCodeModal";
import dayjs from "dayjs";
const GiftCardDetail = () => {
const router = useRouter()
const [gift, setGift] = useState<ShopGift | null>(null)
const [loading, setLoading] = useState(true)
const [showShare, setShowShare] = useState(false)
const [showQRCode, setShowQRCode] = useState(false)
const giftId = router.params.id
useEffect(() => {
if (giftId) {
loadGiftDetail()
}
}, [giftId])
const loadGiftDetail = async () => {
try {
setLoading(true)
const data = await getShopGift(Number(giftId))
setGift(data)
} catch (error) {
console.error('获取礼品卡详情失败:', error)
Taro.showToast({
title: '获取礼品卡详情失败',
icon: 'error'
})
} finally {
setLoading(false)
}
}
// 获取礼品卡类型文本
const getGiftTypeText = (type?: number) => {
switch (type) {
case 10: return '礼品劵'
case 20: return '虚拟礼品卡'
case 30: return '服务礼品卡'
default: return '水票'
}
}
// 获取礼品卡面值显示
const getGiftValueDisplay = () => {
if (!gift || !gift.faceValue) return ''
return `¥${gift.faceValue}`
}
// 获取使用条件文本
const getUsageText = () => {
if (!gift) return ''
if (gift.instructions) {
return gift.instructions
}
switch (gift.type) {
case 10: return '请到指定门店使用此礼品卡'
case 20: return '可在线上平台直接使用'
case 30: return '请联系客服预约服务时间'
default: return '请按照使用说明进行操作'
}
}
// 获取有效期文本
const getValidityText = () => {
if (!gift) return ''
if (gift.validDays) {
return `有效期${gift.validDays}`
} else if (gift.expireTime) {
return `有效期至 ${dayjs(gift.expireTime).format('YYYY年MM月DD日')}`
} else {
return '长期有效'
}
}
// 获取礼品卡状态
const getGiftStatus = () => {
if (!gift) return { status: 0, text: '未知', color: 'default' }
switch (gift.status) {
case 0:
return { status: 0, text: '可使用', color: 'success' }
case 1:
return { status: 1, text: '已使用', color: 'warning' }
case 2:
return { status: 2, text: '已过期', color: 'danger' }
default:
return { status: 0, text: '未知', color: 'default' }
}
}
// 使用礼品卡 - 打开二维码弹窗
const handleUseGift = () => {
if (!gift) return
setShowQRCode(true)
}
// 点击二维码图标
const handleQRCodeClick = () => {
if (!gift) return
setShowQRCode(true)
}
// 复制兑换码
const handleCopyCode = () => {
if (!gift?.code) return
Taro.setClipboardData({
data: gift.code,
success: () => {
Taro.showToast({
title: '兑换码已复制',
icon: 'success'
})
},
fail: () => {
Taro.showToast({
title: '复制失败',
icon: 'error'
})
}
})
}
// 返回上一页
const handleBack = () => {
Taro.navigateBack()
}
if (loading) {
return (
<ConfigProvider>
<View className="flex justify-center items-center h-screen">
<Text>...</Text>
</View>
</ConfigProvider>
)
}
if (!gift) {
return (
<ConfigProvider>
<View className="flex flex-col justify-center items-center h-screen">
<Text className="text-gray-500 mb-4"></Text>
<Button onClick={handleBack}></Button>
</View>
</ConfigProvider>
)
}
const statusInfo = getGiftStatus()
return (
<ConfigProvider>
{/* 礼品卡卡片 */}
<View className="m-4 p-6 rounded-2xl text-white" style={{background: 'linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%)'}}>
<View className="flex items-center justify-between mb-4">
<View className="w-full">
<Text className="text-4xl font-bold">{getGiftValueDisplay()}</Text>
<Text className="opacity-90 mt-1 px-2">{getGiftTypeText(gift.type)}</Text>
</View>
<View
className="p-2 bg-white bg-opacity-20 rounded-lg cursor-pointer"
onClick={handleQRCodeClick}
>
<QrCode size="24" />
</View>
</View>
<Text className="text-xl font-semibold mb-2">{gift.name}</Text>
<Text className="text-base opacity-90 px-2">{gift.description || getUsageText()}</Text>
{/* 兑换码 */}
{gift.code && (
<View className="mt-4 p-3 bg-white bg-opacity-20 rounded-lg">
<View className="flex items-center justify-between">
<View>
<Text className="text-sm opacity-80 px-2"></Text>
<Text className="text-lg font-mono font-bold">{gift.code}</Text>
</View>
<Button
size="small"
fill="outline"
icon={<Copy />}
onClick={handleCopyCode}
className="border-white text-white"
>
</Button>
</View>
</View>
)}
</View>
{/* 详细信息 */}
<View className="bg-white mx-4 rounded-xl p-4">
<Text className="text-lg font-semibold">使</Text>
<View className={'mt-4'}>
<View className="flex items-center mb-3">
<Clock size="16" className="text-gray-400 mr-3" />
<View>
<Text className="text-gray-400 text-sm"></Text>
<Text className="text-blue-500 text-sm px-1">{getValidityText()}</Text>
</View>
</View>
<Divider />
<View className="flex items-center mb-3">
<Gift size="16" className="text-gray-400 mr-3" />
<View>
<Text className="text-gray-400 text-sm"></Text>
<Text className="text-blue-500 text-sm px-1">{getGiftTypeText(gift.type)}</Text>
</View>
</View>
{gift.useLocation && (
<>
<Divider />
<View className="flex items-center">
<Location size="16" className="text-gray-400 mr-3" />
<View>
<Text className="text-gray-400 text-sm">使</Text>
<Text className="text-blue-500 text-sm px-1">{gift.useLocation}</Text>
</View>
</View>
</>
)}
{gift.contactInfo && (
<>
<Divider />
<View className="flex items-center">
<Phone size="16" className="text-gray-400 mr-3" />
<View>
<Text className="text-gray-600 text-sm"></Text>
<Text className="text-gray-900">{gift.contactInfo}</Text>
</View>
</View>
</>
)}
{gift.instructions && (
<>
<Divider />
<View>
<Text className="text-gray-600 text-sm mb-2">使</Text>
<Text className="text-gray-900 leading-relaxed">{gift.instructions}</Text>
</View>
</>
)}
{gift.takeTime && (
<>
<Divider />
<View>
<Text className="text-gray-600 text-sm mb-2">使</Text>
<Text className="text-gray-900">使{dayjs(gift.takeTime).format('YYYY-MM-DD HH:mm')}</Text>
</View>
</>
)}
</View>
</View>
{/* 底部操作按钮 */}
{statusInfo.status === 0 && (
<View className="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-gray-100">
<View className="flex gap-3">
{gift.code && (
<Button
fill="outline"
size="large"
className="flex-1"
icon={<Copy />}
onClick={handleCopyCode}
>
</Button>
)}
<Button
type="primary"
size="large"
className="flex-1"
onClick={handleUseGift}
>
使
</Button>
</View>
</View>
)}
{/* 分享弹窗 */}
{gift && (
<GiftCardShare
visible={showShare}
giftCard={{
id: gift.id || 0,
name: gift.name || '',
type: gift.type || 10,
faceValue: gift.faceValue || '0',
code: gift.code,
description: gift.description
}}
onClose={() => setShowShare(false)}
/>
)}
{/* 二维码弹窗 */}
{gift && (
<SimpleQRCodeModal
visible={showQRCode}
onClose={() => setShowQRCode(false)}
qrContent={gift.code + ''}
giftName={gift.goodsName || gift.name}
faceValue={gift.faceValue}
/>
)}
</ConfigProvider>
);
};
export default GiftCardDetail;