feat(礼品卡): 优化颜色主题并添加核销功能
- 修改礼品卡颜色主题,使用渐变色提升视觉效果 - 添加礼品卡核销功能,包括生成和验证核销码 -优化礼品卡组件,增加状态显示和使用说明 - 新增礼品卡颜色测试页面,用于验证颜色
This commit is contained in:
348
src/user/store/verification.tsx
Normal file
348
src/user/store/verification.tsx
Normal file
@@ -0,0 +1,348 @@
|
||||
import React, { useState } from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { Button, Input, Tag, Divider } from '@nutui/nutui-react-taro'
|
||||
import { Scan, Search } from '@nutui/icons-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
import dayjs from 'dayjs'
|
||||
import {getShopGiftByCode, updateShopGift} from "@/api/shop/shopGift";
|
||||
|
||||
interface VerificationData {
|
||||
type: string
|
||||
giftId: number
|
||||
giftCode: string
|
||||
verificationCode: string
|
||||
faceValue: string
|
||||
timestamp: number
|
||||
expireTime?: string
|
||||
}
|
||||
|
||||
interface GiftCardInfo {
|
||||
id: number
|
||||
name: string
|
||||
goodsName?: string
|
||||
faceValue: string
|
||||
type: number
|
||||
status: number
|
||||
expireTime?: string
|
||||
code: string
|
||||
}
|
||||
|
||||
const StoreVerification: React.FC = () => {
|
||||
const [scanResult, setScanResult] = useState<string>('')
|
||||
const [verificationCode, setVerificationCode] = useState<string>('')
|
||||
const [giftInfo, setGiftInfo] = useState<GiftCardInfo | null>(null)
|
||||
const [verificationResult, setVerificationResult] = useState<'success' | 'failed' | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// 扫码功能
|
||||
const handleScan = () => {
|
||||
Taro.scanCode({
|
||||
success: (res) => {
|
||||
console.log('扫码结果:', res.result)
|
||||
setScanResult(res.result)
|
||||
parseQRCode(res.result)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('扫码失败:', err)
|
||||
Taro.showToast({
|
||||
title: '扫码失败',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 解析二维码数据
|
||||
const parseQRCode = (qrData: string) => {
|
||||
try {
|
||||
const data: VerificationData = JSON.parse(qrData)
|
||||
|
||||
if (data.type === 'gift_card_verification') {
|
||||
setVerificationCode(data.verificationCode)
|
||||
// 模拟获取礼品卡信息
|
||||
mockGetGiftInfo(data)
|
||||
} else {
|
||||
throw new Error('无效的二维码格式')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析二维码失败:', error)
|
||||
Taro.showToast({
|
||||
title: '无效的二维码',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟获取礼品卡信息(实际应该调用API)
|
||||
const mockGetGiftInfo = (data: VerificationData) => {
|
||||
// 这里应该调用后端API验证礼品卡信息
|
||||
const mockGiftInfo: GiftCardInfo = {
|
||||
id: data.giftId,
|
||||
name: '礼品卡',
|
||||
goodsName: '星巴克咖啡券',
|
||||
faceValue: data.faceValue,
|
||||
type: 20,
|
||||
status: 0,
|
||||
expireTime: data.expireTime,
|
||||
code: data.giftCode
|
||||
}
|
||||
|
||||
setGiftInfo(mockGiftInfo)
|
||||
}
|
||||
|
||||
// 手动输入核销码验证
|
||||
const handleManualVerification = async () => {
|
||||
if (!verificationCode.trim()) {
|
||||
Taro.showToast({
|
||||
title: '请输入核销码',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
try {
|
||||
// 这里应该调用后端API验证核销码
|
||||
const giftCard = await getShopGiftByCode(verificationCode.trim())
|
||||
await updateShopGift({
|
||||
...giftCard,
|
||||
status: 1
|
||||
})
|
||||
Taro.showToast({
|
||||
title: '核销成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('验证失败:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟验证核销码
|
||||
const mockVerifyCode = async (code: string) => {
|
||||
// 模拟API调用延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
// 模拟验证逻辑
|
||||
if (code.length === 6 && /^\d+$/.test(code)) {
|
||||
setVerificationResult('success')
|
||||
setGiftInfo({
|
||||
id: 1,
|
||||
name: '礼品卡',
|
||||
goodsName: '星巴克咖啡券',
|
||||
faceValue: '100',
|
||||
type: 20,
|
||||
status: 0,
|
||||
expireTime: '2024-12-31 23:59:59',
|
||||
code: 'SB2024001234567890'
|
||||
})
|
||||
Taro.showToast({
|
||||
title: '验证成功',
|
||||
icon: 'success'
|
||||
})
|
||||
} else {
|
||||
setVerificationResult('failed')
|
||||
Taro.showToast({
|
||||
title: '核销码无效',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 确认核销
|
||||
const handleConfirmVerification = async () => {
|
||||
if (!giftInfo) return
|
||||
|
||||
setLoading(true)
|
||||
try {
|
||||
// 这里应该调用后端API完成核销
|
||||
await mockCompleteVerification(giftInfo.id)
|
||||
|
||||
Taro.showToast({
|
||||
title: '核销成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 重置状态
|
||||
setTimeout(() => {
|
||||
resetForm()
|
||||
}, 2000)
|
||||
} catch (error) {
|
||||
console.error('核销失败:', error)
|
||||
Taro.showToast({
|
||||
title: '核销失败',
|
||||
icon: 'error'
|
||||
})
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟完成核销
|
||||
const mockCompleteVerification = async (giftId: number) => {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
console.log('核销礼品卡:', giftId)
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
setScanResult('')
|
||||
setVerificationCode('')
|
||||
setGiftInfo(null)
|
||||
setVerificationResult(null)
|
||||
}
|
||||
|
||||
// 获取类型文本
|
||||
const getTypeText = (type: number) => {
|
||||
switch (type) {
|
||||
case 10: return '实物礼品卡'
|
||||
case 20: return '虚拟礼品卡'
|
||||
case 30: return '服务礼品卡'
|
||||
default: return '礼品卡'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
{/* 页面标题 */}
|
||||
<View className="bg-white px-4 py-3 border-b border-gray-100">
|
||||
<Text className="text-lg font-bold text-center">
|
||||
礼品卡核销
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-600 text-center mt-1 px-2">
|
||||
门店工作人员核销页面
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 扫码区域 */}
|
||||
<View className="bg-white mx-4 mt-4 p-4 rounded-lg">
|
||||
<View className={'mb-3'}>
|
||||
<Text className="font-bold">扫码核销</Text>
|
||||
</View>
|
||||
<Button
|
||||
size="large"
|
||||
type="primary"
|
||||
icon={<Scan />}
|
||||
onClick={handleScan}
|
||||
block
|
||||
>
|
||||
扫描二维码
|
||||
</Button>
|
||||
|
||||
{scanResult && (
|
||||
<View className="mt-3 p-3 bg-gray-50 rounded">
|
||||
<Text className="text-sm text-gray-600">扫码结果:</Text>
|
||||
<Text className="text-xs text-gray-500 break-all mt-1">
|
||||
{scanResult}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 手动输入区域 */}
|
||||
<View className="bg-white mx-4 mt-4 p-4 rounded-lg">
|
||||
<Text className="font-bold mb-3">手动输入核销码</Text>
|
||||
<View className="flex gap-2">
|
||||
<Input
|
||||
placeholder="请输入8位核销码"
|
||||
value={verificationCode}
|
||||
onChange={setVerificationCode}
|
||||
maxLength={8}
|
||||
className="flex-1"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<Search />}
|
||||
loading={loading}
|
||||
onClick={handleManualVerification}
|
||||
>
|
||||
核销
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 礼品卡信息 */}
|
||||
{giftInfo && (
|
||||
<View className="bg-white mx-4 mt-4 p-4 rounded-lg">
|
||||
<View className="flex justify-between items-center mb-3">
|
||||
<Text className="font-bold">礼品卡信息</Text>
|
||||
{verificationResult === 'success' && (
|
||||
<Tag type="success" size="small">
|
||||
<CheckCircle className="mr-1" />
|
||||
验证成功
|
||||
</Tag>
|
||||
)}
|
||||
{verificationResult === 'failed' && (
|
||||
<Tag type="danger" size="small">
|
||||
<CloseCircle className="mr-1" />
|
||||
验证失败
|
||||
</Tag>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View className="space-y-3">
|
||||
<View className="flex justify-between">
|
||||
<Text className="text-gray-600">商品名称</Text>
|
||||
<Text className="font-medium">
|
||||
{giftInfo.goodsName || giftInfo.name}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between">
|
||||
<Text className="text-gray-600">面值</Text>
|
||||
<Text className="text-lg font-bold text-red-500">
|
||||
¥{giftInfo.faceValue}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between">
|
||||
<Text className="text-gray-600">类型</Text>
|
||||
<Text>{getTypeText(giftInfo.type)}</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between">
|
||||
<Text className="text-gray-600">兑换码</Text>
|
||||
<Text className="font-mono text-sm">{giftInfo.code}</Text>
|
||||
</View>
|
||||
|
||||
{giftInfo.expireTime && (
|
||||
<View className="flex justify-between">
|
||||
<Text className="text-gray-600">有效期至</Text>
|
||||
<Text className="text-orange-600">
|
||||
{dayjs(giftInfo.expireTime).format('YYYY-MM-DD')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<Divider />
|
||||
|
||||
{verificationResult === 'success' && (
|
||||
<Button
|
||||
size="large"
|
||||
type="primary"
|
||||
loading={loading}
|
||||
onClick={handleConfirmVerification}
|
||||
block
|
||||
>
|
||||
确认核销
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 使用说明 */}
|
||||
<View className="bg-blue-50 mx-4 mb-4 p-4 rounded-lg">
|
||||
<Text className="font-bold mb-2 text-gray-500">操作说明:</Text>
|
||||
<View className="space-y-1">
|
||||
<Text className="text-sm text-gray-500">1. 用户出示礼品卡二维码</Text>
|
||||
<Text className="text-sm text-gray-500 ml-2">2. 点击"扫描二维码"进行扫码</Text>
|
||||
<Text className="text-sm text-gray-500 ml-2">3. 或手动输入用户提供的核销码</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default StoreVerification
|
||||
Reference in New Issue
Block a user