fix: исправлен расчет даты переноса задач с периодами повторения
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 54s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 54s
- Добавлена поддержка сокращенных форм единиц времени (mons, min, hrs, wks, yrs и т.д.) - Исправлена обработка недель, которые PostgreSQL возвращает как дни (7 days вместо 1 week) - Добавлено приведение repetition_period к тексту при чтении из БД - Обновлена версия до 3.8.6
This commit is contained in:
@@ -374,7 +374,8 @@ func calculateNextShowAtFromRepetitionDate(repetitionDate string, fromDate time.
|
||||
}
|
||||
|
||||
// calculateNextShowAtFromRepetitionPeriod calculates the next show date by adding repetition_period to fromDate
|
||||
// Format: PostgreSQL INTERVAL string (e.g., "1 day", "2 weeks", "3 months")
|
||||
// Format: PostgreSQL INTERVAL string (e.g., "1 day", "2 weeks", "3 months" or "3 mons")
|
||||
// Note: PostgreSQL may return weeks as days (e.g., "7 days" instead of "1 week")
|
||||
func calculateNextShowAtFromRepetitionPeriod(repetitionPeriod string, fromDate time.Time) *time.Time {
|
||||
if repetitionPeriod == "" {
|
||||
return nil
|
||||
@@ -382,33 +383,45 @@ func calculateNextShowAtFromRepetitionPeriod(repetitionPeriod string, fromDate t
|
||||
|
||||
parts := strings.Fields(strings.TrimSpace(repetitionPeriod))
|
||||
if len(parts) < 2 {
|
||||
log.Printf("calculateNextShowAtFromRepetitionPeriod: invalid format, parts=%v", parts)
|
||||
return nil
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(parts[0])
|
||||
if err != nil {
|
||||
log.Printf("calculateNextShowAtFromRepetitionPeriod: failed to parse value '%s': %v", parts[0], err)
|
||||
return nil
|
||||
}
|
||||
|
||||
unit := strings.ToLower(parts[1])
|
||||
log.Printf("calculateNextShowAtFromRepetitionPeriod: value=%d, unit='%s'", value, unit)
|
||||
|
||||
// Start from fromDate at midnight
|
||||
nextDate := time.Date(fromDate.Year(), fromDate.Month(), fromDate.Day(), 0, 0, 0, 0, fromDate.Location())
|
||||
|
||||
switch unit {
|
||||
case "minute", "minutes":
|
||||
case "minute", "minutes", "mins", "min":
|
||||
nextDate = nextDate.Add(time.Duration(value) * time.Minute)
|
||||
case "hour", "hours":
|
||||
case "hour", "hours", "hrs", "hr":
|
||||
nextDate = nextDate.Add(time.Duration(value) * time.Hour)
|
||||
case "day", "days":
|
||||
// PostgreSQL может возвращать недели как дни (например, "7 days" вместо "1 week")
|
||||
// Если количество дней кратно 7, обрабатываем как недели
|
||||
if value%7 == 0 && value >= 7 {
|
||||
weeks := value / 7
|
||||
nextDate = nextDate.AddDate(0, 0, weeks*7)
|
||||
} else {
|
||||
nextDate = nextDate.AddDate(0, 0, value)
|
||||
case "week", "weeks":
|
||||
}
|
||||
case "week", "weeks", "wks", "wk":
|
||||
nextDate = nextDate.AddDate(0, 0, value*7)
|
||||
case "month", "months":
|
||||
case "month", "months", "mons", "mon":
|
||||
nextDate = nextDate.AddDate(0, value, 0)
|
||||
case "year", "years":
|
||||
log.Printf("calculateNextShowAtFromRepetitionPeriod: added %d months, result=%v", value, nextDate)
|
||||
case "year", "years", "yrs", "yr":
|
||||
nextDate = nextDate.AddDate(value, 0, 0)
|
||||
default:
|
||||
log.Printf("calculateNextShowAtFromRepetitionPeriod: unknown unit '%s'", unit)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7503,7 +7516,7 @@ func (a *App) completeTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var ownerID int
|
||||
|
||||
err = a.DB.QueryRow(`
|
||||
SELECT id, name, reward_message, progression_base, repetition_period, repetition_date, user_id
|
||||
SELECT id, name, reward_message, progression_base, repetition_period::text, repetition_date, user_id
|
||||
FROM tasks
|
||||
WHERE id = $1 AND deleted = FALSE
|
||||
`, taskID).Scan(&task.ID, &task.Name, &rewardMessage, &progressionBase, &repetitionPeriod, &repetitionDate, &ownerID)
|
||||
@@ -7797,14 +7810,17 @@ func (a *App) completeTaskHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Обычный период: обновляем счетчик и last_completed_at, вычисляем next_show_at
|
||||
// next_show_at = last_completed_at + repetition_period
|
||||
now := time.Now()
|
||||
log.Printf("Calculating next_show_at for task %d: repetition_period='%s', fromDate=%v", taskID, repetitionPeriod.String, now)
|
||||
nextShowAt := calculateNextShowAtFromRepetitionPeriod(repetitionPeriod.String, now)
|
||||
if nextShowAt != nil {
|
||||
log.Printf("Calculated next_show_at for task %d: %v", taskID, *nextShowAt)
|
||||
_, err = a.DB.Exec(`
|
||||
UPDATE tasks
|
||||
SET completed = completed + 1, last_completed_at = NOW(), next_show_at = $2
|
||||
WHERE id = $1
|
||||
`, taskID, nextShowAt)
|
||||
} else {
|
||||
log.Printf("Failed to calculate next_show_at for task %d: repetition_period='%s' returned nil", taskID, repetitionPeriod.String)
|
||||
// Если не удалось вычислить дату, обновляем как обычно
|
||||
_, err = a.DB.Exec(`
|
||||
UPDATE tasks
|
||||
@@ -7896,7 +7912,7 @@ func (a *App) completeAndDeleteTaskHandler(w http.ResponseWriter, r *http.Reques
|
||||
var ownerID int
|
||||
|
||||
err = a.DB.QueryRow(`
|
||||
SELECT id, name, reward_message, progression_base, repetition_period, repetition_date, user_id
|
||||
SELECT id, name, reward_message, progression_base, repetition_period::text, repetition_date, user_id
|
||||
FROM tasks
|
||||
WHERE id = $1 AND deleted = FALSE
|
||||
`, taskID).Scan(&task.ID, &task.Name, &rewardMessage, &progressionBase, &repetitionPeriod, &repetitionDate, &ownerID)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "play-life-web",
|
||||
"version": "3.8.5",
|
||||
"version": "3.8.6",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -99,6 +99,7 @@ const calculateNextDateFromRepetitionDate = (repetitionDateStr) => {
|
||||
}
|
||||
|
||||
// Функция для вычисления следующей даты по repetition_period
|
||||
// Поддерживает сокращенные формы единиц времени (например, "mons" для месяцев)
|
||||
const calculateNextDateFromRepetitionPeriod = (repetitionPeriodStr) => {
|
||||
if (!repetitionPeriodStr) return null
|
||||
|
||||
@@ -117,26 +118,43 @@ const calculateNextDateFromRepetitionPeriod = (repetitionPeriodStr) => {
|
||||
switch (unit) {
|
||||
case 'minute':
|
||||
case 'minutes':
|
||||
case 'mins':
|
||||
case 'min':
|
||||
nextDate.setMinutes(nextDate.getMinutes() + value)
|
||||
break
|
||||
case 'hour':
|
||||
case 'hours':
|
||||
case 'hrs':
|
||||
case 'hr':
|
||||
nextDate.setHours(nextDate.getHours() + value)
|
||||
break
|
||||
case 'day':
|
||||
case 'days':
|
||||
// PostgreSQL может возвращать недели как дни (например, "7 days" вместо "1 week")
|
||||
// Если количество дней кратно 7, обрабатываем как недели
|
||||
if (value % 7 === 0 && value >= 7) {
|
||||
const weeks = value / 7
|
||||
nextDate.setDate(nextDate.getDate() + weeks * 7)
|
||||
} else {
|
||||
nextDate.setDate(nextDate.getDate() + value)
|
||||
}
|
||||
break
|
||||
case 'week':
|
||||
case 'weeks':
|
||||
case 'wks':
|
||||
case 'wk':
|
||||
nextDate.setDate(nextDate.getDate() + value * 7)
|
||||
break
|
||||
case 'month':
|
||||
case 'months':
|
||||
case 'mons':
|
||||
case 'mon':
|
||||
nextDate.setMonth(nextDate.getMonth() + value)
|
||||
break
|
||||
case 'year':
|
||||
case 'years':
|
||||
case 'yrs':
|
||||
case 'yr':
|
||||
nextDate.setFullYear(nextDate.getFullYear() + value)
|
||||
break
|
||||
default:
|
||||
|
||||
@@ -139,26 +139,43 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, onRefresh }) {
|
||||
switch (unit) {
|
||||
case 'minute':
|
||||
case 'minutes':
|
||||
case 'mins':
|
||||
case 'min':
|
||||
nextDate.setMinutes(nextDate.getMinutes() + value)
|
||||
break
|
||||
case 'hour':
|
||||
case 'hours':
|
||||
case 'hrs':
|
||||
case 'hr':
|
||||
nextDate.setHours(nextDate.getHours() + value)
|
||||
break
|
||||
case 'day':
|
||||
case 'days':
|
||||
// PostgreSQL может возвращать недели как дни (например, "7 days" вместо "1 week")
|
||||
// Если количество дней кратно 7, обрабатываем как недели
|
||||
if (value % 7 === 0 && value >= 7) {
|
||||
const weeks = value / 7
|
||||
nextDate.setDate(nextDate.getDate() + weeks * 7)
|
||||
} else {
|
||||
nextDate.setDate(nextDate.getDate() + value)
|
||||
}
|
||||
break
|
||||
case 'week':
|
||||
case 'weeks':
|
||||
case 'wks':
|
||||
case 'wk':
|
||||
nextDate.setDate(nextDate.getDate() + value * 7)
|
||||
break
|
||||
case 'month':
|
||||
case 'months':
|
||||
case 'mons':
|
||||
case 'mon':
|
||||
nextDate.setMonth(nextDate.getMonth() + value)
|
||||
break
|
||||
case 'year':
|
||||
case 'years':
|
||||
case 'yrs':
|
||||
case 'yr':
|
||||
nextDate.setFullYear(nextDate.getFullYear() + value)
|
||||
break
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user