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"`
|
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 {
|
type Subtask struct {
|
||||||
Task Task `json:"task"`
|
Task Task `json:"task"`
|
||||||
Rewards []Reward `json:"rewards"`
|
Rewards []Reward `json:"rewards"`
|
||||||
@@ -2769,6 +2777,18 @@ func (a *App) getWeeklyStatsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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)
|
todayScores, err := a.getTodayScores(userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -3202,6 +3222,146 @@ func (a *App) getCurrentWeekScores(userID int) (map[int]float64, error) {
|
|||||||
return scores, nil
|
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 всех нод, созданных сегодня для конкретного пользователя
|
// getTodayScores получает сумму score всех нод, созданных сегодня для конкретного пользователя
|
||||||
// Возвращает map[project_id]today_score для сегодняшнего дня
|
// Возвращает map[project_id]today_score для сегодняшнего дня
|
||||||
func (a *App) getTodayScores(userID int) (map[int]float64, error) {
|
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 для каждой награды и формируем строки для подстановки
|
// Вычисляем score для каждой награды и формируем строки для подстановки
|
||||||
rewardStrings := make(map[int]string)
|
rewardStrings := make(map[int]string)
|
||||||
|
var progressionBasePtr *float64
|
||||||
|
if progressionBase.Valid {
|
||||||
|
progressionBasePtr = &progressionBase.Float64
|
||||||
|
}
|
||||||
for _, reward := range rewards {
|
for _, reward := range rewards {
|
||||||
var score float64
|
score := calculateRewardScore(reward, req.Value, progressionBasePtr)
|
||||||
if reward.UseProgression && progressionBase.Valid && req.Value != nil {
|
|
||||||
score = (*req.Value / progressionBase.Float64) * reward.Value
|
|
||||||
} else {
|
|
||||||
score = reward.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// Формируем строку награды
|
// Формируем строку награды
|
||||||
var rewardStr string
|
var rewardStr string
|
||||||
if score >= 0 {
|
if score >= 0 {
|
||||||
rewardStr = fmt.Sprintf("**%s+%.4g**", reward.ProjectName, score)
|
rewardStr = fmt.Sprintf("**%s+%.4g**", reward.ProjectName, score)
|
||||||
} else {
|
} else {
|
||||||
// Убираем знак минуса из числа (используем абсолютное значение)
|
|
||||||
rewardStr = fmt.Sprintf("**%s-%.4g**", reward.ProjectName, math.Abs(score))
|
rewardStr = fmt.Sprintf("**%s-%.4g**", reward.ProjectName, math.Abs(score))
|
||||||
}
|
}
|
||||||
rewardStrings[reward.Position] = rewardStr
|
rewardStrings[reward.Position] = rewardStr
|
||||||
@@ -9617,16 +9775,14 @@ func (a *App) executeTask(taskID int, userID int, req CompleteTaskRequest) error
|
|||||||
|
|
||||||
// Вычисляем score для наград подзадачи
|
// Вычисляем score для наград подзадачи
|
||||||
subtaskRewardStrings := make(map[int]string)
|
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 {
|
for _, reward := range subtaskRewards {
|
||||||
var score float64
|
score := calculateRewardScore(reward, req.Value, subtaskProgressionBasePtr)
|
||||||
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 rewardStr string
|
var rewardStr string
|
||||||
if score >= 0 {
|
if score >= 0 {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "5.5.0",
|
"version": "5.6.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
Reference in New Issue
Block a user