Розробка системи оцінок і успішності для LMS

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка системи оцінок і успішності для LMS
Середня
~3-5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розроблення системи оцінок та прогресу у LMS

Система оцінок та прогресу відстежує прогрес студента через контент курсу, обчислює підсумкові оцінки з різних видів діяльності (завдання, квізи, участь), генерує звіти про прогрес та підтримує різні схеми оцінювання.

Моделі даних

interface Enrollment {
  id: string;
  userId: string;
  courseId: string;
  enrolledAt: Date;
  completionStatus: 'in_progress' | 'completed' | 'abandoned';
  progressPercent: number;
  finalGrade?: number;
  certificateIssuedAt?: Date;
}

interface LessonProgress {
  id: string;
  enrollmentId: string;
  lessonId: string;
  status: 'not_started' | 'in_progress' | 'completed';
  progressPercent: number;
  completedAt?: Date;
}

interface CourseGradeWeight {
  component: 'assignment' | 'quiz' | 'participation' | 'project';
  weight: number;  // Відсоток підсумкової оцінки
}

interface StudentGrade {
  enrollmentId: string;
  component: string;
  score: number;
  maxScore: number;
  weight: number;
}

Обчислення прогресу курсу

async function calculateCourseProgress(enrollmentId: string): Promise<number> {
  const enrollment = await db.enrollments.findById(enrollmentId);
  const lessonProgress = await db.lessonProgress.findByEnrollment(enrollmentId);
  const lessons = await db.lessons.findByCourse(enrollment.courseId);

  if (lessons.length === 0) return 0;

  const completedLessons = lessonProgress.filter(p => p.status === 'completed').length;
  return Math.round((completedLessons / lessons.length) * 100);
}

app.get('/api/enrollments/:enrollmentId/progress', authenticate, async (req, res) => {
  const enrollment = await db.enrollments.findById(req.params.enrollmentId);
  if (enrollment.userId !== req.user.id) return res.status(403).end();

  const progress = await calculateCourseProgress(req.params.enrollmentId);
  const lessonProgress = await db.lessonProgress.findByEnrollment(req.params.enrollmentId);
  const completedLessons = lessonProgress.filter(p => p.status === 'completed').length;
  const totalLessons = await db.lessons.countByCourse(enrollment.courseId);

  res.json({
    progressPercent: progress,
    completedLessons,
    totalLessons,
    estimatedCompletionDate: progress < 100 ? estimateCompletion(progress) : null,
  });
});

Обчислення підсумкової оцінки

async function calculateFinalGrade(enrollmentId: string): Promise<number> {
  const enrollment = await db.enrollments.findById(enrollmentId);
  const grades = await db.studentGrades.findByEnrollment(enrollmentId);
  const weights = await db.courseGradeWeights.findByCourse(enrollment.courseId);

  let weightedTotal = 0;
  let totalWeight = 0;

  for (const weight of weights) {
    const componentGrades = grades.filter(g => g.component.startsWith(weight.component));
    if (componentGrades.length === 0) continue;

    const avgComponentScore = componentGrades.reduce((sum, g) => {
      return sum + (g.score / g.maxScore) * 100;
    }, 0) / componentGrades.length;

    weightedTotal += avgComponentScore * (weight.weight / 100);
    totalWeight += weight.weight / 100;
  }

  return totalWeight > 0 ? Math.round(weightedTotal / totalWeight) : 0;
}

app.get('/api/enrollments/:enrollmentId/grades', authenticate, async (req, res) => {
  const enrollment = await db.enrollments.findById(req.params.enrollmentId);
  if (enrollment.userId !== req.user.id) return res.status(403).end();

  const finalGrade = await calculateFinalGrade(req.params.enrollmentId);
  const grades = await db.studentGrades.findByEnrollment(req.params.enrollmentId);
  const weights = await db.courseGradeWeights.findByCourse(enrollment.courseId);

  const breakdown = weights.map(w => {
    const componentGrades = grades.filter(g => g.component.startsWith(w.component));
    const avgScore = componentGrades.length > 0
      ? Math.round(componentGrades.reduce((sum, g) => sum + (g.score / g.maxScore) * 100, 0) / componentGrades.length)
      : 0;
    return { component: w.component, score: avgScore, weight: w.weight };
  });

  res.json({
    finalGrade,
    breakdown,
    isPassed: finalGrade >= 70,
  });
});

Компонент звіту про прогрес

function ProgressReport({ enrollmentId }) {
  const [progress, setProgress] = useState<Progress | null>(null);
  const [grades, setGrades] = useState<Grades | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    Promise.all([
      fetch(`/api/enrollments/${enrollmentId}/progress`).then(r => r.json()),
      fetch(`/api/enrollments/${enrollmentId}/grades`).then(r => r.json()),
    ]).then(([p, g]) => {
      setProgress(p);
      setGrades(g);
      setLoading(false);
    });
  }, [enrollmentId]);

  if (loading) return <div>Завантаження...</div>;

  return (
    <div className="max-w-2xl mx-auto p-6 space-y-6">
      <div>
        <h2 className="text-2xl font-bold mb-4">Прогрес курсу</h2>
        <div className="bg-gray-200 rounded-full h-4 overflow-hidden">
          <div
            className="bg-blue-600 h-full transition-all duration-300"
            style={{ width: `${progress?.progressPercent}%` }}
          />
        </div>
        <p className="mt-2 text-sm text-gray-600">
          {progress?.completedLessons}/{progress?.totalLessons} уроків завершено
        </p>
      </div>

      <div>
        <h2 className="text-2xl font-bold mb-4">Оцінки</h2>
        <div className="bg-white border rounded-lg p-4">
          <div className="text-3xl font-bold text-blue-600 mb-4">
            {grades?.finalGrade}% {grades?.isPassed ? '✓' : '✗'}
          </div>

          <div className="space-y-3">
            {grades?.breakdown.map((item) => (
              <div key={item.component} className="flex justify-between items-center">
                <span className="capitalize">{item.component}</span>
                <div className="flex items-center gap-2">
                  <span className="font-semibold">{item.score}%</span>
                  <span className="text-gray-500 text-sm">({item.weight}%)</span>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      {progress?.estimatedCompletionDate && (
        <div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
          <p className="text-sm text-blue-800">
            Орієнтовне завершення: <strong>{progress.estimatedCompletionDate}</strong>
          </p>
        </div>
      )}
    </div>
  );
}

Строки виконання

Базове відстеження прогресу та оцінок — 1 тиждень. З зваженим оцінюванням, детальним розбиттям та прогнозами прогресу — 2–3 тижні.