function ProjectProgressBar({ projectName, totalScore, minGoalScore, maxGoalScore, onProjectClick, projectColor, priority }) { // Вычисляем максимальное значение для шкалы (берем максимум из maxGoalScore и totalScore + 20%) const maxScale = Math.max(maxGoalScore, totalScore * 1.2, 1) // Процентные значения const totalScorePercent = (totalScore / maxScale) * 100 const minGoalPercent = (minGoalScore / maxScale) * 100 const maxGoalPercent = (maxGoalScore / maxScale) * 100 const goalRangePercent = maxGoalPercent - minGoalPercent const normalizedPriority = (() => { if (priority === null || priority === undefined) return null const numeric = Number(priority) return Number.isFinite(numeric) ? numeric : null })() const priorityBonus = (() => { if (normalizedPriority === 1) return 50 if (normalizedPriority === 2) return 35 return 20 })() const goalProgress = (() => { const safeTotal = Number.isFinite(totalScore) ? totalScore : 0 const safeMinGoal = Number.isFinite(minGoalScore) ? minGoalScore : 0 const safeMaxGoal = Number.isFinite(maxGoalScore) ? maxGoalScore : 0 // Если нет валидного minGoal, возвращаем прогресс относительно maxGoal либо 0 if (safeMinGoal <= 0) { if (safeMaxGoal > 0) { return Math.max(0, Math.min((safeTotal / safeMaxGoal) * 100, 100)) } return 0 } // До достижения minGoal растем линейно от 0 до 100% const baseProgress = Math.max(0, Math.min((safeTotal / safeMinGoal) * 100, 100)) // Если maxGoal не задан корректно или еще не достигнут minGoal, показываем базовый прогресс if (safeTotal < safeMinGoal || safeMaxGoal <= safeMinGoal) { return baseProgress } // Между minGoal и maxGoal добавляем бонус в зависимости от приоритета const extraRange = safeMaxGoal - safeMinGoal const extraRatio = Math.min(1, Math.max(0, (safeTotal - safeMinGoal) / extraRange)) const extraProgress = extraRatio * priorityBonus // Выше maxGoal прогресс не растет return Math.min(100 + priorityBonus, 100 + extraProgress) })() const isGoalReached = totalScore >= minGoalScore const isGoalExceeded = totalScore >= maxGoalScore const priorityBorderStyle = normalizedPriority === 1 ? { borderColor: '#d4af37' } : normalizedPriority === 2 ? { borderColor: '#c0c0c0' } : {} const cardBorderClasses = normalizedPriority === 1 || normalizedPriority === 2 ? 'border-2' : 'border border-gray-200/50 hover:border-indigo-300' const cardBaseClasses = 'bg-gradient-to-br from-white to-gray-50 rounded-lg p-3 shadow-sm hover:shadow-md transition-all duration-300 cursor-pointer' const handleClick = () => { if (onProjectClick) { onProjectClick(projectName) } } return (

{projectName}

{totalScore.toFixed(1)}
из {minGoalScore.toFixed(1)} ({goalProgress.toFixed(0)}%)
{/* Диапазон цели (min_goal_score до max_goal_score) */} {minGoalScore > 0 && maxGoalScore > 0 && (
)} {/* Текущее значение (total_score) */}
{/* Индикатор текущего значения */} {totalScorePercent > 0 && (
)}
0 {minGoalScore > 0 && (
Цель: {minGoalScore.toFixed(1)} - {maxGoalScore.toFixed(1)}
)} {maxScale.toFixed(1)}
) } export default ProjectProgressBar