import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Plus, BookOpen, ChevronRight, Trash2, Edit2 } from 'lucide-react'; import { apiClient } from '../../services/apiClient'; import { templateService } from '../../services/templateService'; import { questionBankService } from '../../services/questionBankService'; import { AssessmentTemplate } from '../../types'; interface QuestionBankViewProps { isAdmin?: boolean; } interface QuestionBank { id: string; name: string; description?: string; status: string; templateId?: string; createdAt: string; } export default function QuestionBankView({ isAdmin }: QuestionBankViewProps) { const navigate = useNavigate(); const [banks, setBanks] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); const [showDrawer, setShowDrawer] = useState(false); const [formData, setFormData] = useState({ name: '', description: '', templateId: '' }); const [saving, setSaving] = useState(false); const [templates, setTemplates] = useState([]); const [loadingTemplates, setLoadingTemplates] = useState(false); const [deletingId, setDeletingId] = useState(null); useEffect(() => { fetchData(); }, []); const fetchData = async () => { try { setLoading(true); const res = await apiClient.request('/question-banks', {}); if (!res.ok) throw new Error(res.status.toString()); const data = await res.json(); setBanks(Array.isArray(data) ? data : (data.data || [])); } catch (err: any) { setError(err.message || '加载失败'); } finally { setLoading(false); } }; const openDrawer = () => { setFormData({ name: '', description: '', templateId: '' }); setLoadingTemplates(true); templateService.getAll() .then(data => setTemplates(data)) .catch(err => console.error('加载模板失败:', err)) .finally(() => setLoadingTemplates(false)); setShowDrawer(true); }; const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); if (!formData.name.trim()) return; setSaving(true); try { const payload: any = { name: formData.name, description: formData.description, }; if (formData.templateId) { payload.templateId = formData.templateId; } const res = await apiClient.request('/question-banks', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); if (!res.ok) throw new Error(res.status.toString()); setShowDrawer(false); fetchData(); } catch (err: any) { console.error('创建失败:', err); alert('创建失败: ' + (err.message || '未知错误')); } finally { setSaving(false); } }; const handleDelete = async (e: React.MouseEvent, bankId: string, bankName: string) => { e.stopPropagation(); if (!confirm(`确定要删除题库"${bankName}"吗?此操作不可恢复。`)) return; setDeletingId(bankId); try { await questionBankService.deleteBank(bankId); fetchData(); } catch (err: any) { console.error('删除失败:', err); alert('删除失败: ' + (err.message || '未知错误')); } finally { setDeletingId(null); } }; const handleCardClick = (bank: QuestionBank) => { navigate(`/question-banks/${bank.id}`); }; return (

题库管理

{loading ? (
加载中...
) : error ? (
错误: {error}
) : banks.length === 0 ? (

暂无题库,点击上方按钮创建

) : (
{banks.map((bank) => (
handleCardClick(bank)} >

{bank.name}

{bank.description || '暂无描述'}

{bank.status === 'PUBLISHED' ? '已发布' : bank.status === 'PENDING_REVIEW' ? '待审核' : bank.status === 'REJECTED' ? '已否决' : '草稿'} {new Date(bank.createdAt).toLocaleDateString()}
))}
)} {/* Drawer */} <> {showDrawer && (
setShowDrawer(false)} /> )}

创建题库

setFormData({...formData, name: e.target.value})} className="w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 bg-slate-50" placeholder="输入题库名称" required autoFocus />
setFormData({...formData, description: e.target.value})} className="w-full px-4 py-3 border rounded-xl focus:outline-none focus:ring-2 focus:ring-blue-500 bg-slate-50" placeholder="输入描述" />
{loadingTemplates && 加载中...}
); }