Унификация расчета процентов с бэкендом
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m8s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m8s
This commit is contained in:
@@ -108,9 +108,18 @@ type WeeklyProjectStats struct {
|
|||||||
CalculatedScore float64 `json:"calculated_score"`
|
CalculatedScore float64 `json:"calculated_score"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GroupsProgress struct {
|
||||||
|
Group1 *float64 `json:"group1,omitempty"`
|
||||||
|
Group2 *float64 `json:"group2,omitempty"`
|
||||||
|
Group0 *float64 `json:"group0,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type WeeklyStatsResponse struct {
|
type WeeklyStatsResponse struct {
|
||||||
Total *float64 `json:"total,omitempty"`
|
Total *float64 `json:"total,omitempty"`
|
||||||
Projects []WeeklyProjectStats `json:"projects"`
|
GroupProgress1 *float64 `json:"group_progress_1,omitempty"`
|
||||||
|
GroupProgress2 *float64 `json:"group_progress_2,omitempty"`
|
||||||
|
GroupProgress0 *float64 `json:"group_progress_0,omitempty"`
|
||||||
|
Projects []WeeklyProjectStats `json:"projects"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessagePostRequest struct {
|
type MessagePostRequest struct {
|
||||||
@@ -2538,12 +2547,18 @@ func (a *App) getWeeklyStatsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
projects = append(projects, project)
|
projects = append(projects, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вычисляем проценты для каждой группы
|
||||||
|
groupsProgress := calculateGroupsProgress(groups)
|
||||||
|
|
||||||
// Вычисляем общий процент выполнения
|
// Вычисляем общий процент выполнения
|
||||||
total := calculateOverallProgress(groups)
|
total := calculateOverallProgress(groupsProgress)
|
||||||
|
|
||||||
response := WeeklyStatsResponse{
|
response := WeeklyStatsResponse{
|
||||||
Total: total,
|
Total: total,
|
||||||
Projects: projects,
|
GroupProgress1: groupsProgress.Group1,
|
||||||
|
GroupProgress2: groupsProgress.Group2,
|
||||||
|
GroupProgress0: groupsProgress.Group0,
|
||||||
|
Projects: projects,
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -3727,12 +3742,18 @@ func (a *App) getWeeklyStatsData() (*WeeklyStatsResponse, error) {
|
|||||||
projects = append(projects, project)
|
projects = append(projects, project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вычисляем проценты для каждой группы
|
||||||
|
groupsProgress := calculateGroupsProgress(groups)
|
||||||
|
|
||||||
// Вычисляем общий процент выполнения
|
// Вычисляем общий процент выполнения
|
||||||
total := calculateOverallProgress(groups)
|
total := calculateOverallProgress(groupsProgress)
|
||||||
|
|
||||||
response := WeeklyStatsResponse{
|
response := WeeklyStatsResponse{
|
||||||
Total: total,
|
Total: total,
|
||||||
Projects: projects,
|
GroupProgress1: groupsProgress.Group1,
|
||||||
|
GroupProgress2: groupsProgress.Group2,
|
||||||
|
GroupProgress0: groupsProgress.Group0,
|
||||||
|
Projects: projects,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &response, nil
|
return &response, nil
|
||||||
@@ -3857,12 +3878,18 @@ func (a *App) getWeeklyStatsDataForUser(userID int) (*WeeklyStatsResponse, error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вычисляем проценты для каждой группы
|
||||||
|
groupsProgress := calculateGroupsProgress(groups)
|
||||||
|
|
||||||
// Вычисляем общий процент выполнения
|
// Вычисляем общий процент выполнения
|
||||||
total := calculateOverallProgress(groups)
|
total := calculateOverallProgress(groupsProgress)
|
||||||
|
|
||||||
response := WeeklyStatsResponse{
|
response := WeeklyStatsResponse{
|
||||||
Total: total,
|
Total: total,
|
||||||
Projects: projects,
|
GroupProgress1: groupsProgress.Group1,
|
||||||
|
GroupProgress2: groupsProgress.Group2,
|
||||||
|
GroupProgress0: groupsProgress.Group0,
|
||||||
|
Projects: projects,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &response, nil
|
return &response, nil
|
||||||
@@ -4386,16 +4413,16 @@ func roundToFourDecimals(val float64) float64 {
|
|||||||
return float64(int(val*10000+0.5)) / 10000.0
|
return float64(int(val*10000+0.5)) / 10000.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateOverallProgress вычисляет общий процент выполнения на основе групп проектов по приоритетам
|
// calculateGroupsProgress вычисляет проценты выполнения для каждой группы приоритетов
|
||||||
// groups - карта приоритетов к спискам calculatedScore проектов
|
// groups - карта приоритетов к спискам calculatedScore проектов
|
||||||
// Возвращает указатель на float64 с общим процентом выполнения или nil, если нет данных
|
// Возвращает структуру GroupsProgress с процентами для каждой группы
|
||||||
// Если какая-то группа отсутствует, она считается как 100%
|
// Если какая-то группа отсутствует, она считается как 100%
|
||||||
func calculateOverallProgress(groups map[int][]float64) *float64 {
|
func calculateGroupsProgress(groups map[int][]float64) GroupsProgress {
|
||||||
// Всего есть 3 группы: приоритет 1, приоритет 2, приоритет 0
|
// Всего есть 3 группы: приоритет 1, приоритет 2, приоритет 0
|
||||||
// Вычисляем среднее для каждой группы, если она есть
|
// Вычисляем среднее для каждой группы, если она есть
|
||||||
// Если группы нет, считаем её как 100%
|
// Если группы нет, считаем её как 100%
|
||||||
|
|
||||||
groupAverages := make(map[int]float64)
|
result := GroupsProgress{}
|
||||||
|
|
||||||
// Обрабатываем все 3 возможных приоритета
|
// Обрабатываем все 3 возможных приоритета
|
||||||
priorities := []int{1, 2, 0}
|
priorities := []int{1, 2, 0}
|
||||||
@@ -4403,13 +4430,12 @@ func calculateOverallProgress(groups map[int][]float64) *float64 {
|
|||||||
for _, priorityVal := range priorities {
|
for _, priorityVal := range priorities {
|
||||||
scores, exists := groups[priorityVal]
|
scores, exists := groups[priorityVal]
|
||||||
|
|
||||||
|
var avg float64
|
||||||
if !exists || len(scores) == 0 {
|
if !exists || len(scores) == 0 {
|
||||||
// Если группы нет, считаем как 100%
|
// Если группы нет, считаем как 100%
|
||||||
groupAverages[priorityVal] = 100.0
|
avg = 100.0
|
||||||
} else {
|
} else {
|
||||||
// Вычисляем среднее для группы
|
// Вычисляем среднее для группы
|
||||||
var avg float64
|
|
||||||
|
|
||||||
// Для приоритета 1 и 2 - обычное среднее
|
// Для приоритета 1 и 2 - обычное среднее
|
||||||
if priorityVal == 1 || priorityVal == 2 {
|
if priorityVal == 1 || priorityVal == 2 {
|
||||||
sum := 0.0
|
sum := 0.0
|
||||||
@@ -4431,18 +4457,52 @@ func calculateOverallProgress(groups map[int][]float64) *float64 {
|
|||||||
|
|
||||||
avg = math.Min(120.0, sum)
|
avg = math.Min(120.0, sum)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
groupAverages[priorityVal] = avg
|
// Сохраняем результат в соответствующее поле
|
||||||
|
avgRounded := roundToFourDecimals(avg)
|
||||||
|
switch priorityVal {
|
||||||
|
case 1:
|
||||||
|
result.Group1 = &avgRounded
|
||||||
|
case 2:
|
||||||
|
result.Group2 = &avgRounded
|
||||||
|
case 0:
|
||||||
|
result.Group0 = &avgRounded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculateOverallProgress вычисляет общий процент выполнения на основе процентов групп
|
||||||
|
// groupsProgress - структура с процентами для каждой группы приоритетов
|
||||||
|
// Возвращает указатель на float64 с общим процентом выполнения
|
||||||
|
// Всегда вычисляет среднее всех трех групп (даже если какая-то группа отсутствует, она считается как 100%)
|
||||||
|
func calculateOverallProgress(groupsProgress GroupsProgress) *float64 {
|
||||||
// Находим среднее между всеми тремя группами
|
// Находим среднее между всеми тремя группами
|
||||||
sum := 0.0
|
// Если какая-то группа отсутствует (nil), считаем её как 100%
|
||||||
for _, priorityVal := range priorities {
|
|
||||||
sum += groupAverages[priorityVal]
|
var group1Val, group2Val, group0Val float64
|
||||||
|
|
||||||
|
if groupsProgress.Group1 != nil {
|
||||||
|
group1Val = *groupsProgress.Group1
|
||||||
|
} else {
|
||||||
|
group1Val = 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
overallProgress := sum / 3.0 // Всегда делим на 3, так как групп всегда 3
|
if groupsProgress.Group2 != nil {
|
||||||
|
group2Val = *groupsProgress.Group2
|
||||||
|
} else {
|
||||||
|
group2Val = 100.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if groupsProgress.Group0 != nil {
|
||||||
|
group0Val = *groupsProgress.Group0
|
||||||
|
} else {
|
||||||
|
group0Val = 100.0
|
||||||
|
}
|
||||||
|
|
||||||
|
overallProgress := (group1Val + group2Val + group0Val) / 3.0 // Всегда делим на 3, так как групп всегда 3
|
||||||
overallProgressRounded := roundToFourDecimals(overallProgress)
|
overallProgressRounded := roundToFourDecimals(overallProgress)
|
||||||
total := &overallProgressRounded
|
total := &overallProgressRounded
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "3.25.3",
|
"version": "3.25.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -307,6 +307,9 @@ function AppContent() {
|
|||||||
// Обрабатываем ответ: приходит массив с одним объектом [{total: ..., projects: [...]}]
|
// Обрабатываем ответ: приходит массив с одним объектом [{total: ..., projects: [...]}]
|
||||||
let projects = []
|
let projects = []
|
||||||
let total = null
|
let total = null
|
||||||
|
let groupProgress1 = null
|
||||||
|
let groupProgress2 = null
|
||||||
|
let groupProgress0 = null
|
||||||
|
|
||||||
if (Array.isArray(jsonData) && jsonData.length > 0) {
|
if (Array.isArray(jsonData) && jsonData.length > 0) {
|
||||||
// Если ответ - массив, проверяем первый элемент
|
// Если ответ - массив, проверяем первый элемент
|
||||||
@@ -316,6 +319,9 @@ function AppContent() {
|
|||||||
if (firstItem.projects && Array.isArray(firstItem.projects)) {
|
if (firstItem.projects && Array.isArray(firstItem.projects)) {
|
||||||
projects = firstItem.projects
|
projects = firstItem.projects
|
||||||
total = firstItem.total !== undefined ? firstItem.total : null
|
total = firstItem.total !== undefined ? firstItem.total : null
|
||||||
|
groupProgress1 = firstItem.group_progress_1 !== undefined ? firstItem.group_progress_1 : null
|
||||||
|
groupProgress2 = firstItem.group_progress_2 !== undefined ? firstItem.group_progress_2 : null
|
||||||
|
groupProgress0 = firstItem.group_progress_0 !== undefined ? firstItem.group_progress_0 : null
|
||||||
} else {
|
} else {
|
||||||
// Если это просто массив проектов
|
// Если это просто массив проектов
|
||||||
projects = jsonData
|
projects = jsonData
|
||||||
@@ -328,11 +334,17 @@ function AppContent() {
|
|||||||
// Если ответ - объект напрямую
|
// Если ответ - объект напрямую
|
||||||
projects = jsonData.projects || jsonData.data || []
|
projects = jsonData.projects || jsonData.data || []
|
||||||
total = jsonData.total !== undefined ? jsonData.total : null
|
total = jsonData.total !== undefined ? jsonData.total : null
|
||||||
|
groupProgress1 = jsonData.group_progress_1 !== undefined ? jsonData.group_progress_1 : null
|
||||||
|
groupProgress2 = jsonData.group_progress_2 !== undefined ? jsonData.group_progress_2 : null
|
||||||
|
groupProgress0 = jsonData.group_progress_0 !== undefined ? jsonData.group_progress_0 : null
|
||||||
}
|
}
|
||||||
|
|
||||||
setCurrentWeekData({
|
setCurrentWeekData({
|
||||||
projects: Array.isArray(projects) ? projects : [],
|
projects: Array.isArray(projects) ? projects : [],
|
||||||
total: total
|
total: total,
|
||||||
|
group_progress_1: groupProgress1,
|
||||||
|
group_progress_2: groupProgress2,
|
||||||
|
group_progress_0: groupProgress0
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCurrentWeekError(err.message)
|
setCurrentWeekError(err.message)
|
||||||
|
|||||||
@@ -356,46 +356,27 @@ function CurrentWeek({ onProjectClick, data, loading, error, onRetry, allProject
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Вычисляем процент выполнения для каждой группы
|
// Получаем проценты групп из API данных
|
||||||
const calculateGroupProgress = (projects) => {
|
const mainProgress = (() => {
|
||||||
if (projects.length === 0) return 0
|
const rawValue = data?.group_progress_1
|
||||||
|
const parsedValue = rawValue === undefined || rawValue === null ? null : parseFloat(rawValue)
|
||||||
let totalProgress = 0
|
return Number.isFinite(parsedValue) && parsedValue >= 0 ? parsedValue : 0
|
||||||
let validProjects = 0
|
|
||||||
|
|
||||||
projects.forEach(project => {
|
|
||||||
const safeTotal = Number.isFinite(project.total_score) ? project.total_score : 0
|
|
||||||
const safeMinGoal = Number.isFinite(project.min_goal_score) ? project.min_goal_score : 0
|
|
||||||
|
|
||||||
if (safeMinGoal > 0) {
|
|
||||||
const projectProgress = Math.min((safeTotal / safeMinGoal) * 100, 100)
|
|
||||||
totalProgress += projectProgress
|
|
||||||
validProjects++
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return validProjects > 0 ? totalProgress / validProjects : 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainProgress = calculateGroupProgress(priorityGroups.main)
|
|
||||||
const importantProgress = calculateGroupProgress(priorityGroups.important)
|
|
||||||
const othersProgress = calculateGroupProgress(priorityGroups.others)
|
|
||||||
|
|
||||||
// Пересчитываем общий прогресс как среднее от групповых процентов
|
|
||||||
const recalculatedOverallProgress = (() => {
|
|
||||||
const groups = []
|
|
||||||
if (priorityGroups.main.length > 0) groups.push(mainProgress)
|
|
||||||
if (priorityGroups.important.length > 0) groups.push(importantProgress)
|
|
||||||
if (priorityGroups.others.length > 0) groups.push(othersProgress)
|
|
||||||
|
|
||||||
if (groups.length === 0) return null
|
|
||||||
|
|
||||||
const average = groups.reduce((sum, progress) => sum + progress, 0) / groups.length
|
|
||||||
return Math.max(0, average) // Убираем ограничение на 100% для текста
|
|
||||||
})()
|
})()
|
||||||
|
|
||||||
// Используем пересчитанный общий прогресс вместо API данных
|
const importantProgress = (() => {
|
||||||
const displayOverallProgress = recalculatedOverallProgress !== null ? recalculatedOverallProgress : (hasProgressData ? overallProgress : null)
|
const rawValue = data?.group_progress_2
|
||||||
|
const parsedValue = rawValue === undefined || rawValue === null ? null : parseFloat(rawValue)
|
||||||
|
return Number.isFinite(parsedValue) && parsedValue >= 0 ? parsedValue : 0
|
||||||
|
})()
|
||||||
|
|
||||||
|
const othersProgress = (() => {
|
||||||
|
const rawValue = data?.group_progress_0
|
||||||
|
const parsedValue = rawValue === undefined || rawValue === null ? null : parseFloat(rawValue)
|
||||||
|
return Number.isFinite(parsedValue) && parsedValue >= 0 ? parsedValue : 0
|
||||||
|
})()
|
||||||
|
|
||||||
|
// Используем общий прогресс из API данных
|
||||||
|
const displayOverallProgress = overallProgress
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative pt-8">
|
<div className="relative pt-8">
|
||||||
|
|||||||
Reference in New Issue
Block a user