import React, { useState } from 'react'; import { View, Text } from '@tarojs/components'; import { Button, Popup, Loading } from '@nutui/nutui-react-taro'; import { Scan, Close, Success, Failure } from '@nutui/icons-react-taro'; import Taro from '@tarojs/taro'; import { parseQRContent, confirmQRLogin } from '@/api/passport/qr-login'; import { useUser } from '@/hooks/useUser'; export interface QRScanModalProps { /** 是否显示弹窗 */ visible: boolean; /** 关闭弹窗回调 */ onClose: () => void; /** 扫码成功回调 */ onSuccess?: (result: any) => void; /** 扫码失败回调 */ onError?: (error: string) => void; /** 弹窗标题 */ title?: string; /** 描述文本 */ description?: string; /** 是否自动确认登录 */ autoConfirm?: boolean; } /** * 二维码扫描弹窗组件(用于扫码登录) */ const QRScanModal: React.FC = ({ visible, onClose, onSuccess, onError, title = '扫描登录二维码', description = '扫描网页端显示的登录二维码', autoConfirm = true }) => { const { user } = useUser(); const [loading, setLoading] = useState(false); const [status, setStatus] = useState<'idle' | 'scanning' | 'confirming' | 'success' | 'error'>('idle'); const [errorMsg, setErrorMsg] = useState(''); // 开始扫码 const handleScan = async () => { if (!user?.userId) { onError?.('请先登录小程序'); return; } try { setLoading(true); setStatus('scanning'); setErrorMsg(''); // 扫码 const scanResult = await new Promise((resolve, reject) => { Taro.scanCode({ onlyFromCamera: true, scanType: ['qrCode'], success: (res) => { if (res.result) { resolve(res.result); } else { reject(new Error('扫码结果为空')); } }, fail: (err) => { reject(new Error(err.errMsg || '扫码失败')); } }); }); // 解析二维码内容 const token = parseQRContent(scanResult); if (!token) { throw new Error('无效的登录二维码'); } if (autoConfirm) { // 自动确认登录 setStatus('confirming'); const result = await confirmQRLogin({ token, userId: user.userId, platform: 'wechat', wechatInfo: { nickname: user.nickname, avatar: user.avatar } }); if (result.success) { setStatus('success'); onSuccess?.(result); // 显示成功提示 Taro.showToast({ title: '登录确认成功', icon: 'success' }); // 延迟关闭 setTimeout(() => { onClose(); setStatus('idle'); }, 1500); } else { throw new Error(result.message || '登录确认失败'); } } else { // 只返回扫码结果 onSuccess?.(scanResult); onClose(); setStatus('idle'); } } catch (error: any) { setStatus('error'); const errorMessage = error.message || '操作失败'; setErrorMsg(errorMessage); onError?.(errorMessage); } finally { setLoading(false); } }; // 重试 const handleRetry = () => { setStatus('idle'); setErrorMsg(''); handleScan(); }; // 关闭弹窗 const handleClose = () => { setStatus('idle'); setErrorMsg(''); setLoading(false); onClose(); }; // 获取状态显示内容 const getStatusContent = () => { switch (status) { case 'scanning': return { icon: , title: '正在扫码...', description: '请将二维码对准摄像头' }; case 'confirming': return { icon: , title: '正在确认登录...', description: '请稍候,正在为您确认登录' }; case 'success': return { icon: , title: '登录确认成功', description: '网页端将自动完成登录' }; case 'error': return { icon: , title: '操作失败', description: errorMsg || '请重试' }; default: return { icon: , title, description }; } }; const statusContent = getStatusContent(); return ( {/* 关闭按钮 */} {status !== 'scanning' && status !== 'confirming' && ( )} {/* 图标 */} {statusContent.icon} {/* 标题 */} {statusContent.title} {/* 描述 */} {statusContent.description} {/* 操作按钮 */} {status === 'idle' && ( )} {status === 'error' && ( )} {(status === 'scanning' || status === 'confirming') && ( )} {loading} ); }; export default QRScanModal;