- 修复消息组件JSX.Element类型错误,改为React.ReactNode - 完善审核历史页面类型定义和API接口调用 - 优化验证码组件,移除备用验证码逻辑避免无限循环 - 简化系统设置页面,仅保留基本设置和外观设置 - 修复用户管理页面编辑模态框数据加载和CRUD操作 - 移除废弃的作物推荐组件文件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
135 lines
4.4 KiB
TypeScript
135 lines
4.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useCallback,useRef } from 'react';
|
|
import { RefreshCw } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { getCaptchaApiV1AuthCaptchaGet } from '@/lib/api/sdk.gen';
|
|
import type { CaptchaResponse } from '@/lib/api/types.gen';
|
|
|
|
interface CaptchaInputProps {
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
onCaptchaChange?: (captchaData: CaptchaResponse | null) => void;
|
|
className?: string;
|
|
instanceId?: string;
|
|
}
|
|
|
|
export function CaptchaInput({ value, onChange, onCaptchaChange, className = '', instanceId = 'default' }: CaptchaInputProps) {
|
|
const [captchaData, setCaptchaData] = useState<CaptchaResponse | null>(null);
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
const isInitialized = useRef(false);
|
|
|
|
|
|
// 初始化验证码
|
|
useEffect(() => {
|
|
if (!isInitialized.current) {
|
|
isInitialized.current = true;
|
|
const initialFetch = async () => {
|
|
console.log(`[CaptchaInput-${instanceId}] 初始化获取验证码...`);
|
|
setLoading(true);
|
|
setError('');
|
|
|
|
try {
|
|
const response = await getCaptchaApiV1AuthCaptchaGet();
|
|
console.log(`[CaptchaInput-${instanceId}] API验证码获取成功:`, response);
|
|
setCaptchaData(response.data);
|
|
if (onCaptchaChange) {
|
|
onCaptchaChange(response.data);
|
|
}
|
|
} catch (err) {
|
|
console.error(`[CaptchaInput-${instanceId}] 验证码获取失败:`, err);
|
|
setError('获取验证码失败,请重试');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
initialFetch();
|
|
}
|
|
}, [instanceId, onCaptchaChange]);
|
|
|
|
const fetchCaptcha = useCallback(async () => {
|
|
console.log(`[CaptchaInput-${instanceId}] 刷新验证码...`);
|
|
setLoading(true);
|
|
setError('');
|
|
|
|
try {
|
|
const response = await getCaptchaApiV1AuthCaptchaGet();
|
|
console.log(`[CaptchaInput-${instanceId}] API验证码获取成功:`, response);
|
|
setCaptchaData(response.data);
|
|
if (onCaptchaChange) {
|
|
onCaptchaChange(response.data);
|
|
}
|
|
} catch (err) {
|
|
console.error(`[CaptchaInput-${instanceId}] 验证码获取失败:`, err);
|
|
setError('获取验证码失败,请重试');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [instanceId, onCaptchaChange]);
|
|
|
|
const handleRefresh = () => {
|
|
onChange(''); // 清空验证码输入
|
|
fetchCaptcha();
|
|
};
|
|
|
|
const handleCaptchaChange = (inputValue: string) => {
|
|
onChange(inputValue);
|
|
};
|
|
|
|
return (
|
|
<div className={`flex gap-2 ${className}`}>
|
|
<Input
|
|
type="text"
|
|
placeholder="请输入验证码"
|
|
value={value}
|
|
onChange={(e) => handleCaptchaChange(e.target.value.toUpperCase())}
|
|
maxLength={4}
|
|
className="flex-1"
|
|
disabled={loading}
|
|
/>
|
|
<div className="flex gap-2 items-center">
|
|
{loading ? (
|
|
<div className="w-[120px] h-10 border border-gray-300 rounded flex items-center justify-center bg-gray-100">
|
|
<div className="w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin"></div>
|
|
</div>
|
|
) : error ? (
|
|
<div className="w-[120px] h-10 border border-red-300 rounded flex items-center justify-center bg-red-50">
|
|
<span className="text-xs text-red-500">获取失败</span>
|
|
</div>
|
|
) : (
|
|
<div
|
|
className="h-10 w-[120px] border border-gray-300 rounded cursor-pointer hover:opacity-80 transition-opacity overflow-hidden"
|
|
onClick={handleRefresh}
|
|
title="点击刷新验证码"
|
|
>
|
|
{captchaData && (
|
|
<img
|
|
src={captchaData.image}
|
|
alt="验证码"
|
|
className="w-full h-full object-cover"
|
|
onError={(e) => {
|
|
// 如果图片加载失败,隐藏错误图片
|
|
e.currentTarget.style.display = 'none';
|
|
setError('图片加载失败');
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
)}
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
size="icon"
|
|
onClick={handleRefresh}
|
|
disabled={loading}
|
|
title="刷新验证码"
|
|
>
|
|
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |