Files
mp-10550/src/components/QRLoginScanner.tsx
赵忠林 cbcf591f71 feat(admin): 实现管理员模式切换和扫码登录功能
- 新增管理员模式切换方案,统一管理所有管理员功能
- 实现扫码登录功能,支持用户通过小程序扫描网页端二维码快速登录
- 添加管理员面板组件,集中展示所有管理员功能
- 开发扫码登录按钮和扫描器组件,方便集成到不同页面
- 优化用户界面设计,提高管理员用户的使用体验
2025-09-01 14:26:00 +08:00

183 lines
4.5 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 React from 'react';
import { View, Text } from '@tarojs/components';
import { Button, Loading } from '@nutui/nutui-react-taro';
import { Scan, Success, Failure } from '@nutui/icons-react-taro';
import { useQRLogin, ScanLoginState } from '@/hooks/useQRLogin';
export interface QRLoginScannerProps {
/** 扫码成功回调 */
onSuccess?: (result: any) => void;
/** 扫码失败回调 */
onError?: (error: string) => void;
/** 自定义样式类名 */
className?: string;
/** 按钮文本 */
buttonText?: string;
/** 是否显示状态信息 */
showStatus?: boolean;
}
/**
* 扫码登录组件
*/
const QRLoginScanner: React.FC<QRLoginScannerProps> = ({
onSuccess,
onError,
className = '',
buttonText = '扫码登录',
showStatus = true
}) => {
const {
state,
error,
result,
isLoading,
startScan,
cancel,
reset,
canScan
} = useQRLogin();
// 处理扫码成功
React.useEffect(() => {
if (state === ScanLoginState.SUCCESS && result) {
onSuccess?.(result);
}
}, [state, result, onSuccess]);
// 处理扫码失败
React.useEffect(() => {
if (state === ScanLoginState.ERROR && error) {
onError?.(error);
}
}, [state, error, onError]);
// 获取状态显示内容
const getStatusContent = () => {
switch (state) {
case ScanLoginState.SCANNING:
return (
<View className="flex items-center justify-center text-blue-500">
<Loading className="mr-2" />
<Text>...</Text>
</View>
);
case ScanLoginState.CONFIRMING:
return (
<View className="flex items-center justify-center text-orange-500">
<Loading className="mr-2" />
<Text>...</Text>
</View>
);
case ScanLoginState.SUCCESS:
return (
<View className="flex items-center justify-center text-green-500">
<Success className="mr-2" />
<Text></Text>
</View>
);
case ScanLoginState.ERROR:
return (
<View className="flex items-center justify-center text-red-500">
<Failure className="mr-2" />
<Text>{error || '扫码登录失败'}</Text>
</View>
);
default:
return null;
}
};
// 获取按钮状态
const getButtonProps = () => {
const disabled = !canScan() || isLoading;
switch (state) {
case ScanLoginState.SCANNING:
case ScanLoginState.CONFIRMING:
return {
loading: true,
disabled: true,
text: state === ScanLoginState.SCANNING ? '扫码中...' : '确认中...',
onClick: cancel
};
case ScanLoginState.SUCCESS:
return {
loading: false,
disabled: false,
text: '重新扫码',
onClick: reset
};
case ScanLoginState.ERROR:
return {
loading: false,
disabled: false,
text: '重试',
onClick: startScan
};
default:
return {
loading: false,
disabled,
text: disabled ? '请先登录' : buttonText,
onClick: startScan
};
}
};
const buttonProps = getButtonProps();
return (
<View className={`qr-login-scanner ${className}`}>
{/* 扫码按钮 */}
<Button
type="primary"
size="large"
loading={buttonProps.loading}
disabled={buttonProps.disabled}
onClick={buttonProps.onClick}
className="w-full"
>
{!buttonProps.loading && (
<Scan className="mr-2" />
)}
{buttonProps.text}
</Button>
{/* 状态显示 */}
{showStatus && (
<View className="mt-4 text-center">
{getStatusContent()}
</View>
)}
{/* 成功结果显示 */}
{state === ScanLoginState.SUCCESS && result && (
<View className="mt-4 p-4 bg-green-50 rounded-lg">
<Text className="text-sm text-green-700">
{result.userInfo?.nickname || result.userInfo?.userId}
</Text>
</View>
)}
{/* 使用说明 */}
{state === ScanLoginState.IDLE && (
<View className="mt-4 text-center">
<Text className="text-xs text-gray-500">
</Text>
</View>
)}
</View>
);
};
export default QRLoginScanner;