v3.1.0: Оптимизация загрузки списка задач - все данные в одном запросе, добавлены индикаторы подзадач и прогрессии
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 40s

This commit is contained in:
poignatov
2026-01-06 14:54:37 +03:00
parent 28d8148665
commit 0ea531889d
5 changed files with 138 additions and 114 deletions

View File

@@ -28,6 +28,7 @@ import (
"github.com/gorilla/mux"
"github.com/joho/godotenv"
_ "github.com/lib/pq"
"github.com/lib/pq"
"github.com/robfig/cron/v3"
"golang.org/x/crypto/bcrypt"
)
@@ -207,6 +208,10 @@ type Task struct {
RewardMessage *string `json:"reward_message,omitempty"`
ProgressionBase *float64 `json:"progression_base,omitempty"`
RepetitionPeriod *string `json:"repetition_period,omitempty"`
// Дополнительные поля для списка задач (без omitempty чтобы всегда передавались)
ProjectNames []string `json:"project_names"`
SubtasksCount int `json:"subtasks_count"`
HasProgression bool `json:"has_progression"`
}
type Reward struct {
@@ -6248,13 +6253,40 @@ func (a *App) getTasksHandler(w http.ResponseWriter, r *http.Request) {
return
}
// Запрос с получением всех необходимых данных для группировки и отображения
query := `
SELECT id, name, completed, last_completed_at, repetition_period::text
FROM tasks
WHERE user_id = $1 AND parent_task_id IS NULL AND deleted = FALSE
SELECT
t.id,
t.name,
t.completed,
t.last_completed_at,
t.repetition_period::text,
t.progression_base,
COALESCE((
SELECT COUNT(*)
FROM tasks st
WHERE st.parent_task_id = t.id AND st.deleted = FALSE
), 0) as subtasks_count,
COALESCE(
(SELECT array_agg(DISTINCT p.name) FILTER (WHERE p.name IS NOT NULL)
FROM reward_configs rc
JOIN projects p ON rc.project_id = p.id
WHERE rc.task_id = t.id),
ARRAY[]::text[]
) as project_names,
COALESCE(
(SELECT array_agg(DISTINCT p.name) FILTER (WHERE p.name IS NOT NULL)
FROM tasks st
JOIN reward_configs rc ON rc.task_id = st.id
JOIN projects p ON rc.project_id = p.id
WHERE st.parent_task_id = t.id AND st.deleted = FALSE),
ARRAY[]::text[]
) as subtask_project_names
FROM tasks t
WHERE t.user_id = $1 AND t.parent_task_id IS NULL AND t.deleted = FALSE
ORDER BY
CASE WHEN last_completed_at IS NULL OR last_completed_at::date < CURRENT_DATE THEN 0 ELSE 1 END,
name
CASE WHEN t.last_completed_at IS NULL OR t.last_completed_at::date < CURRENT_DATE THEN 0 ELSE 1 END,
t.name
`
rows, err := a.DB.Query(query, userID)
@@ -6270,8 +6302,21 @@ func (a *App) getTasksHandler(w http.ResponseWriter, r *http.Request) {
var task Task
var lastCompletedAt sql.NullString
var repetitionPeriod sql.NullString
var progressionBase sql.NullFloat64
var projectNames pq.StringArray
var subtaskProjectNames pq.StringArray
err := rows.Scan(&task.ID, &task.Name, &task.Completed, &lastCompletedAt, &repetitionPeriod)
err := rows.Scan(
&task.ID,
&task.Name,
&task.Completed,
&lastCompletedAt,
&repetitionPeriod,
&progressionBase,
&task.SubtasksCount,
&projectNames,
&subtaskProjectNames,
)
if err != nil {
log.Printf("Error scanning task: %v", err)
continue
@@ -6283,6 +6328,30 @@ func (a *App) getTasksHandler(w http.ResponseWriter, r *http.Request) {
if repetitionPeriod.Valid {
task.RepetitionPeriod = &repetitionPeriod.String
}
if progressionBase.Valid {
task.HasProgression = true
task.ProgressionBase = &progressionBase.Float64
} else {
task.HasProgression = false
}
// Объединяем проекты из основной задачи и подзадач
allProjects := make(map[string]bool)
for _, pn := range projectNames {
if pn != "" {
allProjects[pn] = true
}
}
for _, pn := range subtaskProjectNames {
if pn != "" {
allProjects[pn] = true
}
}
task.ProjectNames = make([]string, 0, len(allProjects))
for pn := range allProjects {
task.ProjectNames = append(task.ProjectNames, pn)
}
tasks = append(tasks, task)
}