"use client"; import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { X, CheckCircle2, Search, FileText, Users, Calendar, Clock, ArrowRight, Loader2 } from 'lucide-react'; import { ExamDto, ClassDto } from '../../../../UI_DTO'; import { examService, orgService, assignmentService } from '@/services/api'; import { useToast } from '@/components/ui/Toast'; interface CreateAssignmentModalProps { onClose: () => void; onSuccess: () => void; } export const CreateAssignmentModal: React.FC = ({ onClose, onSuccess }) => { const [step, setStep] = useState(1); const [loading, setLoading] = useState(false); const { showToast } = useToast(); const [exams, setExams] = useState([]); const [classes, setClasses] = useState([]); const [selectedExam, setSelectedExam] = useState(null); const [selectedClassIds, setSelectedClassIds] = useState([]); const [config, setConfig] = useState({ title: '', startDate: new Date().toISOString().split('T')[0], dueDate: new Date(Date.now() + 7 * 86400000).toISOString().split('T')[0] }); useEffect(() => { examService.getMyExams().then(res => setExams(res.items)); orgService.getClasses().then(setClasses); }, []); useEffect(() => { if (selectedExam && !config.title) { setConfig(prev => ({ ...prev, title: selectedExam.title + ' - 作业' })); } }, [selectedExam]); const handlePublish = async () => { setLoading(true); try { await assignmentService.publishAssignment({ examId: selectedExam?.id, classIds: selectedClassIds, ...config }); showToast('作业发布成功!', 'success'); onSuccess(); } catch (e) { showToast('发布失败,请重试', 'error'); } finally { setLoading(false); } }; const steps = [ { num: 1, label: '选择试卷' }, { num: 2, label: '选择班级' }, { num: 3, label: '发布设置' } ]; return (
{/* Fix: cast props to any to avoid framer-motion type errors */}

发布新作业

{steps.map((s) => (
= s.num ? 'bg-blue-600 border-blue-600 text-white' : 'bg-white border-gray-200 text-gray-400'}`}> {step > s.num ? : s.num}
= s.num ? 'text-blue-600' : 'text-gray-400'}`}>{s.label}
))}
{step === 1 && ( // Fix: cast props to any to avoid framer-motion type errors
{exams.map(exam => (
setSelectedExam(exam)} className={`p-4 rounded-xl border cursor-pointer transition-all flex items-center gap-4 ${selectedExam?.id === exam.id ? 'border-blue-500 bg-blue-50 ring-1 ring-blue-500' : 'border-gray-200 hover:border-blue-300 hover:bg-gray-50'} `} >

{exam.title}

{exam.questionCount} 题 {exam.duration} 分钟 总分 {exam.totalScore}
{selectedExam?.id === exam.id && }
))}
)} {step === 2 && ( // Fix: cast props to any to avoid framer-motion type errors {classes.map(cls => { const isSelected = selectedClassIds.includes(cls.id); return (
{ setSelectedClassIds(prev => isSelected ? prev.filter(id => id !== cls.id) : [...prev, cls.id] ); }} className={`p-4 rounded-xl border cursor-pointer transition-all flex items-start gap-4 ${isSelected ? 'border-blue-500 bg-blue-50 ring-1 ring-blue-500' : 'border-gray-200 hover:border-blue-300 hover:bg-gray-50'} `} >

{cls.name}

{cls.studentCount} 名学生

{isSelected && }
) })}
)} {step === 3 && ( // Fix: cast props to any to avoid framer-motion type errors
setConfig({...config, title: e.target.value})} className="w-full p-3 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-500 transition-colors" />
setConfig({...config, startDate: e.target.value})} className="w-full pl-10 pr-3 py-3 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-500 transition-colors" />
setConfig({...config, dueDate: e.target.value})} className="w-full pl-10 pr-3 py-3 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-500 transition-colors" />

发布预览

  • • 试卷:{selectedExam?.title}
  • • 对象:共选中 {selectedClassIds.length} 个班级
  • • 时长:{selectedExam?.duration} 分钟
)}
{step > 1 ? ( ) : (
)} {step < 3 ? ( ) : ( )}
); };