From e457113fc9bf5a974acf12141695bf21bf40e547 Mon Sep 17 00:00:00 2001 From: poignatov Date: Wed, 4 Mar 2026 10:13:58 +0300 Subject: [PATCH] =?UTF-8?q?5.6.0:=20=D0=A3=D1=87=D1=91=D1=82=20=D0=B1?= =?UTF-8?q?=D0=B0=D0=BB=D0=BB=D0=BE=D0=B2=20=D0=B8=D0=B7=20=D0=B4=D1=80?= =?UTF-8?q?=D0=B0=D1=84=D1=82=D0=BE=D0=B2=20=D0=B2=20=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=81=D1=82=D0=B8=D0=BA=D0=B5=20=D0=BD=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- VERSION | 2 +- play-life-backend/main.go | 188 +++++++++++++++++++++++++++++++++---- play-life-web/package.json | 2 +- 3 files changed, 174 insertions(+), 18 deletions(-) diff --git a/VERSION b/VERSION index d50359d..1bc788d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.5.0 +5.6.0 diff --git a/play-life-backend/main.go b/play-life-backend/main.go index bb6cfbf..2bc55d4 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -353,6 +353,14 @@ type Reward struct { UseProgression bool `json:"use_progression"` } +// calculateRewardScore вычисляет score для награды на основе progression +func calculateRewardScore(reward Reward, progressionValue *float64, progressionBase *float64) float64 { + if reward.UseProgression && progressionBase != nil && progressionValue != nil && *progressionBase != 0 { + return (*progressionValue / *progressionBase) * reward.Value + } + return reward.Value +} + type Subtask struct { Task Task `json:"task"` Rewards []Reward `json:"rewards"` @@ -2769,6 +2777,18 @@ func (a *App) getWeeklyStatsHandler(w http.ResponseWriter, r *http.Request) { return } + // Получаем pending баллы из драфтов с auto_complete=true + draftPendingScores, err := a.getDraftPendingScores(userID) + if err != nil { + log.Printf("Error getting draft pending scores: %v", err) + // Не прерываем выполнение, продолжаем без pending scores + } else { + // Добавляем pending scores к currentWeekScores + for projectID, pendingScore := range draftPendingScores { + currentWeekScores[projectID] += pendingScore + } + } + // Получаем сегодняшние приросты todayScores, err := a.getTodayScores(userID) if err != nil { @@ -3202,6 +3222,146 @@ func (a *App) getCurrentWeekScores(userID int) (map[int]float64, error) { return scores, nil } +// getDraftPendingScores получает потенциальные баллы из драфтов с auto_complete=true +// Эти баллы будут начислены при автовыполнении задач в конце дня +// Возвращает map[project_id]pending_score +func (a *App) getDraftPendingScores(userID int) (map[int]float64, error) { + // Получаем все драфты с auto_complete=true для пользователя + // Включаем progression_base из задачи для расчёта score + query := ` + SELECT + td.task_id, + td.progression_value, + t.progression_base + FROM task_drafts td + JOIN tasks t ON td.task_id = t.id + WHERE td.user_id = $1 AND td.auto_complete = TRUE AND t.deleted = FALSE + ` + + rows, err := a.DB.Query(query, userID) + if err != nil { + log.Printf("Error querying draft pending scores: %v", err) + return nil, fmt.Errorf("error querying draft pending scores: %w", err) + } + defer rows.Close() + + scores := make(map[int]float64) + + for rows.Next() { + var taskID int + var progressionValue sql.NullFloat64 + var progressionBase sql.NullFloat64 + + if err := rows.Scan(&taskID, &progressionValue, &progressionBase); err != nil { + log.Printf("Error scanning draft row: %v", err) + continue + } + + // Получаем reward_configs для основной задачи + rewardRows, err := a.DB.Query(` + SELECT rc.project_id, rc.value, rc.use_progression + FROM reward_configs rc + WHERE rc.task_id = $1 + `, taskID) + if err != nil { + log.Printf("Error querying task rewards for draft: %v", err) + continue + } + + var progressionValuePtr *float64 + if progressionValue.Valid { + progressionValuePtr = &progressionValue.Float64 + } + var progressionBasePtr *float64 + if progressionBase.Valid { + progressionBasePtr = &progressionBase.Float64 + } + + for rewardRows.Next() { + var projectID int + var rewardValue float64 + var useProgression bool + + if err := rewardRows.Scan(&projectID, &rewardValue, &useProgression); err != nil { + log.Printf("Error scanning reward row: %v", err) + continue + } + + reward := Reward{ + Value: rewardValue, + UseProgression: useProgression, + } + score := calculateRewardScore(reward, progressionValuePtr, progressionBasePtr) + scores[projectID] += score + } + rewardRows.Close() + + // Получаем отмеченные подзадачи из драфта + subtaskRows, err := a.DB.Query(` + SELECT tds.subtask_id, t.progression_base + FROM task_draft_subtasks tds + JOIN task_drafts td ON tds.task_draft_id = td.id + JOIN tasks t ON tds.subtask_id = t.id + WHERE td.task_id = $1 AND td.user_id = $2 + `, taskID, userID) + if err != nil { + log.Printf("Error querying draft subtasks: %v", err) + continue + } + + for subtaskRows.Next() { + var subtaskID int + var subtaskProgressionBase sql.NullFloat64 + + if err := subtaskRows.Scan(&subtaskID, &subtaskProgressionBase); err != nil { + log.Printf("Error scanning subtask row: %v", err) + continue + } + + // Определяем progression_base для подзадачи + var subtaskProgressionBasePtr *float64 + if subtaskProgressionBase.Valid { + subtaskProgressionBasePtr = &subtaskProgressionBase.Float64 + } else if progressionBase.Valid { + subtaskProgressionBasePtr = &progressionBase.Float64 + } + + // Получаем награды подзадачи + subtaskRewardRows, err := a.DB.Query(` + SELECT rc.project_id, rc.value, rc.use_progression + FROM reward_configs rc + WHERE rc.task_id = $1 + `, subtaskID) + if err != nil { + log.Printf("Error querying subtask rewards: %v", err) + continue + } + + for subtaskRewardRows.Next() { + var projectID int + var rewardValue float64 + var useProgression bool + + if err := subtaskRewardRows.Scan(&projectID, &rewardValue, &useProgression); err != nil { + log.Printf("Error scanning subtask reward row: %v", err) + continue + } + + reward := Reward{ + Value: rewardValue, + UseProgression: useProgression, + } + score := calculateRewardScore(reward, progressionValuePtr, subtaskProgressionBasePtr) + scores[projectID] += score + } + subtaskRewardRows.Close() + } + subtaskRows.Close() + } + + return scores, nil +} + // getTodayScores получает сумму score всех нод, созданных сегодня для конкретного пользователя // Возвращает map[project_id]today_score для сегодняшнего дня func (a *App) getTodayScores(userID int) (map[int]float64, error) { @@ -9471,20 +9631,18 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error // Вычисляем score для каждой награды и формируем строки для подстановки rewardStrings := make(map[int]string) + var progressionBasePtr *float64 + if progressionBase.Valid { + progressionBasePtr = &progressionBase.Float64 + } for _, reward := range rewards { - var score float64 - if reward.UseProgression && progressionBase.Valid && req.Value != nil { - score = (*req.Value / progressionBase.Float64) * reward.Value - } else { - score = reward.Value - } + score := calculateRewardScore(reward, req.Value, progressionBasePtr) // Формируем строку награды var rewardStr string if score >= 0 { rewardStr = fmt.Sprintf("**%s+%.4g**", reward.ProjectName, score) } else { - // Убираем знак минуса из числа (используем абсолютное значение) rewardStr = fmt.Sprintf("**%s-%.4g**", reward.ProjectName, math.Abs(score)) } rewardStrings[reward.Position] = rewardStr @@ -9617,16 +9775,14 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error // Вычисляем score для наград подзадачи subtaskRewardStrings := make(map[int]string) + var subtaskProgressionBasePtr *float64 + if subtaskProgressionBase.Valid { + subtaskProgressionBasePtr = &subtaskProgressionBase.Float64 + } else if progressionBase.Valid { + subtaskProgressionBasePtr = &progressionBase.Float64 + } for _, reward := range subtaskRewards { - var score float64 - if reward.UseProgression && subtaskProgressionBase.Valid && req.Value != nil { - score = (*req.Value / subtaskProgressionBase.Float64) * reward.Value - } else if reward.UseProgression && progressionBase.Valid && req.Value != nil { - // Если у подзадачи нет progression_base, используем основной - score = (*req.Value / progressionBase.Float64) * reward.Value - } else { - score = reward.Value - } + score := calculateRewardScore(reward, req.Value, subtaskProgressionBasePtr) var rewardStr string if score >= 0 { diff --git a/play-life-web/package.json b/play-life-web/package.json index 553be4f..e2fec46 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "5.5.0", + "version": "5.6.0", "type": "module", "scripts": { "dev": "vite",