"use client"; import {useState, useEffect, useCallback, useRef} from "react"; import { Plus, Search, Loader2, Pencil, Trash2, Sparkles, ChevronLeft, ChevronRight, X, } from "lucide-react"; import {Button} from "@/components/ui/button"; import {useToast} from "@/components/ui/toast"; interface WordItem { id: number; word: string; english: string; createTime?: string; updateTime?: string; } interface Pagination { page: number; pageSize: number; total: number; totalPages: number; } // Modal 组件 function Modal({ open, onClose, title, children, }: { open: boolean; onClose: () => void; title: string; children: React.ReactNode; }) { if (!open) return null; return (
{/* Backdrop */}
{/* Content */}

{title}

{children}
); } export default function TranslationPage() { const [words, setWords] = useState([]); const [pagination, setPagination] = useState({ page: 1, pageSize: 20, total: 0, totalPages: 0, }); const [search, setSearch] = useState(""); const [loading, setLoading] = useState(false); const [showAddModal, setShowAddModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [editingWord, setEditingWord] = useState(null); const [newWord, setNewWord] = useState({word: "", english: ""}); const [editForm, setEditForm] = useState({word: "", english: ""}); const [aiTranslating, setAiTranslating] = useState(false); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const {addToast} = useToast(); // 搜索防抖定时器 const searchTimerRef = useRef(null); // 禁止背景滚动 useEffect(() => { if (showAddModal || showEditModal) { document.body.style.overflow = "hidden"; } else { document.body.style.overflow = ""; } return () => { document.body.style.overflow = ""; }; }, [showAddModal, showEditModal]); // 获取词组列表 const fetchWords = useCallback(async () => { setLoading(true); setError(null); try { const params = new URLSearchParams({ page: pagination.page.toString(), pageSize: pagination.pageSize.toString(), }); if (search) params.set("search", search); const response = await fetch(`/api/words?${params}`); const result = await response.json(); if (result.success) { setWords(result.data); setPagination(result.pagination); } else { setError(result.error || "获取数据失败"); } } catch (error) { console.error("Failed to fetch words:", error); setError("网络错误,请检查连接"); } finally { setLoading(false); } }, [pagination.page, pagination.pageSize, search]); useEffect(() => { fetchWords(); }, [fetchWords]); // 搜索(防抖 300ms) const handleSearch = () => { if (searchTimerRef.current) { clearTimeout(searchTimerRef.current); } searchTimerRef.current = setTimeout(() => { setPagination((prev) => ({...prev, page: 1})); fetchWords(); }, 300); }; // 添加词组 const handleAdd = async () => { if (!newWord.word || !newWord.english) return; setSaving(true); try { const response = await fetch("/api/words", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(newWord), }); if (response.ok) { setNewWord({word: "", english: ""}); setShowAddModal(false); fetchWords(); } } catch (error) { console.error("Failed to add word:", error); } finally { setSaving(false); } }; // 打开编辑弹窗 const handleEdit = (word: WordItem) => { setEditingWord(word); setEditForm({word: word.word, english: word.english}); setShowEditModal(true); }; // 保存编辑 const handleSave = async () => { if (!editingWord || !editForm.word || !editForm.english) return; setSaving(true); try { const response = await fetch(`/api/words/${editingWord.id}`, { method: "PATCH", headers: {"Content-Type": "application/json"}, body: JSON.stringify(editForm), }); if (response.ok) { setShowEditModal(false); setEditingWord(null); fetchWords(); } } catch (error) { console.error("Failed to update word:", error); } finally { setSaving(false); } }; // 删除词组 const handleDelete = async (id: number) => { if (!confirm("确定要删除这个词组吗?")) return; try { const response = await fetch(`/api/words/${id}`, { method: "DELETE", }); if (response.ok) { fetchWords(); } } catch (error) { console.error("Failed to delete word:", error); } }; // AI 翻译 const handleAiTranslate = async (target: "add" | "edit") => { const source = target === "add" ? newWord.word : editForm.word; if (!source.trim()) return; setAiTranslating(true); try { // 使用 AI 翻译 API const response = await fetch(`/api/ai/translate?word=${encodeURIComponent(source.trim())}`); const result = await response.json(); if (result.english) { if (target === "add") { setNewWord((prev) => ({...prev, english: result.english})); } else { setEditForm((prev) => ({...prev, english: result.english})); } } else { addToast({type: "error", title: "翻译失败", description: result.error || "未找到翻译结果"}); } } catch (error) { console.error("AI translation error:", error); addToast({type: "error", title: "翻译失败", description: "请检查 AI 配置"}); } finally { setAiTranslating(false); } }; return (
{/*标题和按钮*/}

翻译词库

管理翻译词组对照表

{/* 搜索输入框 */}
setSearch(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleSearch()} placeholder="搜索中文或英文..." className="w-full rounded-md border border-input bg-background py-2 pl-10 pr-4 text-sm" />
{/* 错误提示 */} {error && (

{error}

)} {/* 词组列表 */}
{loading ? ( ) : words.length === 0 ? ( ) : ( words.map((word) => ( )) )}
中文 英文 操作
暂无词组,点击上方添加按钮新建
{word.word} {word.english}
{/* 分页 */} {pagination.totalPages > 1 && (
共 {pagination.total} 条,第 {pagination.page}/{pagination.totalPages} 页
{pagination.page} / {pagination.totalPages}
)}
{/* 添加弹窗 */} setShowAddModal(false)} title="添加词组">
setNewWord({...newWord, word: e.target.value})} placeholder="输入中文" className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm" />
setNewWord({...newWord, english: e.target.value})} placeholder="输入英文" className="flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm" />
{/* 编辑弹窗 */} setShowEditModal(false)} title="编辑词组">
setEditForm({...editForm, word: e.target.value})} className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm" />
setEditForm({...editForm, english: e.target.value})} className="flex-1 rounded-md border border-input bg-background px-3 py-2 text-sm" />
); }