fix: 修复系统模块TypeScript类型错误和组件功能问题

- 修复消息组件JSX.Element类型错误,改为React.ReactNode
- 完善审核历史页面类型定义和API接口调用
- 优化验证码组件,移除备用验证码逻辑避免无限循环
- 简化系统设置页面,仅保留基本设置和外观设置
- 修复用户管理页面编辑模态框数据加载和CRUD操作
- 移除废弃的作物推荐组件文件

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-12 17:28:11 +08:00
parent dcd7ddeb71
commit dfc29ce01f
21 changed files with 379 additions and 769 deletions

View File

@@ -1,6 +1,6 @@
'use client';
import { useState, useEffect, useCallback } from 'react';
import { useState, useEffect, useCallback,useRef } from 'react';
import { RefreshCw } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -12,121 +12,66 @@ interface CaptchaInputProps {
onChange: (value: string) => void;
onCaptchaChange?: (captchaData: CaptchaResponse | null) => void;
className?: string;
instanceId?: string;
}
export function CaptchaInput({ value, onChange, onCaptchaChange, className = '' }: CaptchaInputProps) {
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('');
onChange(''); // 清空验证码输入
try {
const response = await getCaptchaApiV1AuthCaptchaGet();
console.log('API验证码获取成功:', response);
console.log(`[CaptchaInput-${instanceId}] API验证码获取成功:`, response);
setCaptchaData(response.data);
if (onCaptchaChange) {
onCaptchaChange(response.data);
}
} catch (err) {
console.error('验证码获取失败:', err);
// 如果API失败使用备用验证码
const fallbackCaptcha = generateFallbackCaptcha();
console.log('生成备用验证码:', fallbackCaptcha);
setCaptchaData(fallbackCaptcha);
if (onCaptchaChange) {
onCaptchaChange(fallbackCaptcha);
}
setError(''); // 清除错误状态,因为备用验证码已生成
console.error(`[CaptchaInput-${instanceId}] 验证码获取失败:`, err);
setError('获取验证码失败,请重试');
} finally {
setLoading(false);
}
};
const generateFallbackCaptcha = (): CaptchaResponse => {
// 备用验证码生成使用Canvas
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
let text = '';
for (let i = 0; i < 4; i++) {
text += chars.charAt(Math.floor(Math.random() * chars.length));
}
const canvas = document.createElement('canvas');
canvas.width = 120;
canvas.height = 40;
const ctx = canvas.getContext('2d');
if (!ctx) {
return {
captcha_id: 'fallback-' + Date.now(),
image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='
};
}
// 背景
ctx.fillStyle = '#f0f0f0';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 干扰线
for (let i = 0; i < 3; i++) {
ctx.strokeStyle = `rgba(${Math.random() * 100}, ${Math.random() * 100}, ${Math.random() * 100}, 0.3)`;
ctx.beginPath();
ctx.moveTo(Math.random() * canvas.width, Math.random() * canvas.height);
ctx.lineTo(Math.random() * canvas.width, Math.random() * canvas.height);
ctx.stroke();
}
// 干扰点
for (let i = 0; i < 30; i++) {
ctx.fillStyle = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 0.3)`;
ctx.beginPath();
ctx.arc(
Math.random() * canvas.width,
Math.random() * canvas.height,
1,
0,
2 * Math.PI
);
ctx.fill();
}
// 验证码文字
ctx.font = 'bold 24px Arial';
ctx.textBaseline = 'middle';
for (let i = 0; i < text.length; i++) {
const char = text[i];
const x = 20 + i * 25;
const y = 20 + (Math.random() - 0.5) * 6;
const angle = (Math.random() - 0.5) * 0.4;
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
// 随机颜色
const colors = ['#16a34a', '#2563eb', '#dc2626', '#ea580c', '#8b5cf6'];
ctx.fillStyle = colors[Math.floor(Math.random() * colors.length)];
ctx.fillText(char, 0, 0);
ctx.restore();
}
return {
captcha_id: 'fallback-' + Date.now(),
image: canvas.toDataURL()
};
}, [onCaptchaChange, onChange]);
useEffect(() => {
fetchCaptcha();
}, [fetchCaptcha]);
}, [instanceId, onCaptchaChange]);
const handleRefresh = () => {
onChange(''); // 清空验证码输入
fetchCaptcha();
};