5.6.0: Учёт баллов из драфтов в статистике недели
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m26s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m26s
This commit is contained in:
@@ -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)
|
||||
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
|
||||
var progressionBasePtr *float64
|
||||
if progressionBase.Valid {
|
||||
progressionBasePtr = &progressionBase.Float64
|
||||
}
|
||||
for _, reward := range rewards {
|
||||
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)
|
||||
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
|
||||
var subtaskProgressionBasePtr *float64
|
||||
if subtaskProgressionBase.Valid {
|
||||
subtaskProgressionBasePtr = &subtaskProgressionBase.Float64
|
||||
} else if progressionBase.Valid {
|
||||
subtaskProgressionBasePtr = &progressionBase.Float64
|
||||
}
|
||||
for _, reward := range subtaskRewards {
|
||||
score := calculateRewardScore(reward, req.Value, subtaskProgressionBasePtr)
|
||||
|
||||
var rewardStr string
|
||||
if score >= 0 {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "play-life-web",
|
||||
"version": "5.5.0",
|
||||
"version": "5.6.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
Reference in New Issue
Block a user