75 lines
2.2 KiB
JavaScript
75 lines
2.2 KiB
JavaScript
import React from "react";
|
||
import { FormControl, FormErrorMessage, HStack, Input, Button, Spinner } from "@chakra-ui/react";
|
||
import { logger } from "../../utils/logger";
|
||
|
||
/**
|
||
* 通用验证码输入组件
|
||
*/
|
||
export default function VerificationCodeInput({
|
||
value,
|
||
onChange,
|
||
onSendCode,
|
||
countdown,
|
||
isLoading,
|
||
isSending,
|
||
error,
|
||
placeholder = "请输入6位验证码",
|
||
buttonText = "获取验证码",
|
||
countdownText = (count) => `${count}s`,
|
||
colorScheme = "green",
|
||
isRequired = true
|
||
}) {
|
||
// 包装 onSendCode,确保所有错误都被捕获,防止被 ErrorBoundary 捕获
|
||
const handleSendCode = async () => {
|
||
try {
|
||
if (onSendCode) {
|
||
await onSendCode();
|
||
}
|
||
} catch (error) {
|
||
// 错误已经在父组件处理,这里只需要防止未捕获的 Promise rejection
|
||
logger.error('VerificationCodeInput', 'handleSendCode', error, {
|
||
hasOnSendCode: !!onSendCode,
|
||
countdown,
|
||
isLoading,
|
||
isSending
|
||
});
|
||
}
|
||
};
|
||
|
||
// 计算按钮显示的文本(避免在 JSX 中使用条件渲染)
|
||
const getButtonText = () => {
|
||
if (isSending) {
|
||
return "发送中";
|
||
}
|
||
if (countdown > 0) {
|
||
return countdownText(countdown);
|
||
}
|
||
return buttonText;
|
||
};
|
||
|
||
return (
|
||
<FormControl isRequired={isRequired} isInvalid={!!error}>
|
||
<HStack>
|
||
<Input
|
||
name="verificationCode"
|
||
value={value}
|
||
onChange={onChange}
|
||
placeholder={placeholder}
|
||
maxLength={6}
|
||
/>
|
||
<Button
|
||
type="button"
|
||
colorScheme={colorScheme}
|
||
onClick={handleSendCode}
|
||
isDisabled={countdown > 0 || isLoading || isSending}
|
||
minW="120px"
|
||
leftIcon={isSending ? <Spinner size="sm" /> : undefined}
|
||
>
|
||
{getButtonText()}
|
||
</Button>
|
||
</HStack>
|
||
<FormErrorMessage>{error}</FormErrorMessage>
|
||
</FormControl>
|
||
);
|
||
}
|