From 67bd87e12a9d118f119a261a1caad92828c7dd1f Mon Sep 17 00:00:00 2001 From: Kai Date: Mon, 16 Feb 2026 15:06:34 +0100 Subject: [PATCH] =?UTF-8?q?Fortlaufende=20Zyklus-Planung=20und=20Periodenl?= =?UTF-8?q?ogik=20einf=C3=BChren?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server/calendar.go | 69 ++++++++++++++++++---------------- cmd/server/db.go | 34 ++++++++++++----- cmd/server/domain.go | 22 +++++++++++ cmd/server/handlers_actions.go | 25 +++++++----- cmd/server/handlers_pages.go | 5 ++- cmd/server/main.go | 3 +- cmd/server/types.go | 13 +++++++ templates/dashboard.html | 7 +++- templates/planning.html | 23 +++++++++--- 9 files changed, 138 insertions(+), 63 deletions(-) diff --git a/cmd/server/calendar.go b/cmd/server/calendar.go index 6512453..0419f28 100644 --- a/cmd/server/calendar.go +++ b/cmd/server/calendar.go @@ -13,14 +13,16 @@ func buildTasksForDay(plans []Plan, crops []Crop, products []Product, stepMap ma return tasks } -func buildCalendar(plans []Plan, crops []Crop, products []Product, stepMap map[int64][]CropStep, customTasks []CustomTask, doneMap map[string]bool, startMonth, startDay, daysPerMonth, spanMonths int) []CalendarMonth { +func buildCalendar(plans []Plan, crops []Crop, products []Product, stepMap map[int64][]CropStep, customTasks []CustomTask, doneMap map[string]bool, startPeriod, startDay, daysPerMonth, spanMonths int) []CalendarMonth { var out []CalendarMonth + startCycle := periodCycle(startPeriod) for offset := 0; offset < spanMonths; offset++ { - month := wrapMonth(startMonth + offset) - yearOffset := (startMonth - 1 + offset) / 12 + period := startPeriod + offset + month := periodMonth(period) + yearOffset := periodCycle(period) - startCycle label := monthNames[month-1] if yearOffset > 0 { - label = fmt.Sprintf("%s (+%d Jahr)", label, yearOffset) + label = fmt.Sprintf("%s (+%d Zyklus)", label, yearOffset) } fromDay := 1 @@ -30,7 +32,7 @@ func buildCalendar(plans []Plan, crops []Crop, products []Product, stepMap map[i var days []CalendarDay for d := fromDay; d <= daysPerMonth; d++ { - items := collectTasksForDate(plans, crops, products, stepMap, customTasks, month, d, yearOffset) + items := collectTasksForDate(plans, crops, products, stepMap, customTasks, period, d, yearOffset) applyCompletion(items, doneMap) sortTasks(items) days = append(days, CalendarDay{Day: d, Tasks: items, Groups: groupTasksByField(items)}) @@ -65,11 +67,12 @@ func groupTasksByField(tasks []Task) []FieldTaskGroup { return out } -func collectTasksForDate(plans []Plan, crops []Crop, products []Product, stepMap map[int64][]CropStep, customTasks []CustomTask, month, day, yearOffset int) []Task { +func collectTasksForDate(plans []Plan, crops []Crop, products []Product, stepMap map[int64][]CropStep, customTasks []CustomTask, period, day, yearOffset int) []Task { var tasks []Task + month := periodMonth(period) for _, p := range plans { - tasks = append(tasks, expandPlanDayTasks(p, stepMap[p.CropID], month, day, yearOffset)...) + tasks = append(tasks, expandPlanDayTasks(p, stepMap[p.CropID], period, day, yearOffset)...) } if day == 1 { for _, c := range crops { @@ -102,7 +105,7 @@ func collectTasksForDate(plans []Plan, crops []Crop, products []Product, stepMap } } for _, c := range customTasks { - if c.Month == month && c.Day == day && c.YearOffset == yearOffset { + if c.TaskPeriod == period && c.Day == day { field := c.TargetName if strings.TrimSpace(field) == "" { field = "Allgemein" @@ -113,13 +116,13 @@ func collectTasksForDate(plans []Plan, crops []Crop, products []Product, stepMap } tasks = append(tasks, Task{ UID: fmt.Sprintf("custom:%d", c.ID), - Type: "Aufgabe", - Field: field, - Message: msg, - Month: month, - Day: day, - YearOffset: yearOffset, - SortOrder: 40, + Type: "Aufgabe", + Field: field, + Message: msg, + Month: periodMonth(period), + Day: day, + YearOffset: yearOffset, + SortOrder: 40, }) } } @@ -127,18 +130,18 @@ func collectTasksForDate(plans []Plan, crops []Crop, products []Product, stepMap return tasks } -func expandPlanDayTasks(p Plan, steps []CropStep, month, day, yearOffset int) []Task { +func expandPlanDayTasks(p Plan, steps []CropStep, period, day, yearOffset int) []Task { field := p.TargetName if strings.TrimSpace(field) == "" { field = "Unbekanntes Feld" } + month := periodMonth(period) var out []Task - baseHarvest := p.HarvestMonth - if p.StartMonth == month && p.StartDay == day && yearOffset == 0 { + if p.StartPeriod == period && p.StartDay == day { out = append(out, Task{ - UID: fmt.Sprintf("plan:%d:sow:0", p.ID), + UID: fmt.Sprintf("plan:%d:sow:%d", p.ID, p.StartPeriod), Type: "Aussaat", Field: field, Message: withOptionalNote(fmt.Sprintf("Aussaat %s", p.CropName), p.Notes), @@ -149,21 +152,21 @@ func expandPlanDayTasks(p Plan, steps []CropStep, month, day, yearOffset int) [] }) } - harvestMonths := []int{baseHarvest} + harvestPeriods := []int{p.HarvestPeriod} if p.RegrowEnabled { maxExtra := p.RegrowCycles if maxExtra == 0 { maxExtra = 24 } for i := 1; i <= maxExtra; i++ { - harvestMonths = append(harvestMonths, wrapMonth(baseHarvest+(i*p.HarvestDistance()))) + harvestPeriods = append(harvestPeriods, p.HarvestPeriod+(i*p.HarvestDistance())) } } - harvestMonths = uniqueMonths(harvestMonths) + harvestPeriods = uniquePeriods(harvestPeriods) - for idx, hm := range harvestMonths { - if hm == month && p.HarvestDay == day { - uid := fmt.Sprintf("plan:%d:harvest:%d", p.ID, idx) + for _, harvestPeriod := range harvestPeriods { + if harvestPeriod == period && p.HarvestDay == day { + uid := fmt.Sprintf("plan:%d:harvest:%d", p.ID, harvestPeriod) out = append(out, Task{ UID: uid, Type: "Ernte", @@ -180,10 +183,10 @@ func expandPlanDayTasks(p Plan, steps []CropStep, month, day, yearOffset int) [] for _, s := range steps { switch s.Phase { case "pre": - taskMonth := wrapMonth(p.StartMonth - s.MonthOffset) - if taskMonth == month && p.StartDay == day && yearOffset == 0 { + taskPeriod := p.StartPeriod - s.MonthOffset + if taskPeriod == period && p.StartDay == day { out = append(out, Task{ - UID: fmt.Sprintf("plan:%d:pre:%d", p.ID, s.ID), + UID: fmt.Sprintf("plan:%d:pre:%d:%d", p.ID, s.ID, taskPeriod), Type: "Vorbereitung", Field: field, Message: s.Title, @@ -194,11 +197,11 @@ func expandPlanDayTasks(p Plan, steps []CropStep, month, day, yearOffset int) [] }) } case "post": - for idx, hm := range harvestMonths { - taskMonth := wrapMonth(hm + s.MonthOffset) - if taskMonth == month && p.HarvestDay == day { + for _, harvestPeriod := range harvestPeriods { + taskPeriod := harvestPeriod + s.MonthOffset + if taskPeriod == period && p.HarvestDay == day { out = append(out, Task{ - UID: fmt.Sprintf("plan:%d:post:%d:%d", p.ID, s.ID, idx), + UID: fmt.Sprintf("plan:%d:post:%d:%d", p.ID, s.ID, taskPeriod), Type: "Nachbereitung", Field: field, Message: s.Title, @@ -252,7 +255,7 @@ func sortTasks(tasks []Task) { }) } -func uniqueMonths(values []int) []int { +func uniquePeriods(values []int) []int { seen := make(map[int]bool) var out []int for _, v := range values { diff --git a/cmd/server/db.go b/cmd/server/db.go index 9d0def6..52b7548 100644 --- a/cmd/server/db.go +++ b/cmd/server/db.go @@ -11,12 +11,15 @@ func ensureSchema(db *sql.DB) error { id TINYINT PRIMARY KEY, days_per_month INT NOT NULL DEFAULT 2, current_month TINYINT NOT NULL DEFAULT 1, + current_cycle INT NOT NULL DEFAULT 0, current_day TINYINT NOT NULL DEFAULT 1 )`, `ALTER TABLE settings ADD COLUMN IF NOT EXISTS current_month TINYINT NOT NULL DEFAULT 1`, + `ALTER TABLE settings ADD COLUMN IF NOT EXISTS current_cycle INT NOT NULL DEFAULT 0`, `ALTER TABLE settings ADD COLUMN IF NOT EXISTS current_day TINYINT NOT NULL DEFAULT 1`, - `INSERT INTO settings(id,days_per_month,current_month,current_day) VALUES (1,2,1,1) ON DUPLICATE KEY UPDATE id=id`, + `INSERT INTO settings(id,days_per_month,current_month,current_cycle,current_day) VALUES (1,2,1,0,1) ON DUPLICATE KEY UPDATE id=id`, `UPDATE settings SET current_month=1 WHERE current_month < 1 OR current_month > 12`, + `UPDATE settings SET current_cycle=0 WHERE current_cycle < 0`, `UPDATE settings SET current_day=1 WHERE current_day < 1`, `CREATE TABLE IF NOT EXISTS fields( @@ -71,6 +74,7 @@ func ensureSchema(db *sql.DB) error { id BIGINT AUTO_INCREMENT PRIMARY KEY, template_id BIGINT NULL, title VARCHAR(140) NOT NULL, + task_period INT NOT NULL DEFAULT 0, month TINYINT NOT NULL, day TINYINT NOT NULL, year_offset SMALLINT NOT NULL DEFAULT 0, @@ -95,8 +99,10 @@ func ensureSchema(db *sql.DB) error { target_ref VARCHAR(80) NOT NULL DEFAULT '', target_name VARCHAR(140) NOT NULL DEFAULT '', crop_id BIGINT NOT NULL, + start_period INT NOT NULL DEFAULT 0, start_month TINYINT NOT NULL, start_day TINYINT NOT NULL, + harvest_period INT NOT NULL DEFAULT 0, harvest_month TINYINT NOT NULL, harvest_day TINYINT NOT NULL, notes VARCHAR(255) NOT NULL DEFAULT '', @@ -107,6 +113,12 @@ func ensureSchema(db *sql.DB) error { `ALTER TABLE plans MODIFY COLUMN field_id BIGINT NULL`, `ALTER TABLE plans ADD COLUMN IF NOT EXISTS target_ref VARCHAR(80) NOT NULL DEFAULT '' AFTER field_id`, `ALTER TABLE plans ADD COLUMN IF NOT EXISTS target_name VARCHAR(140) NOT NULL DEFAULT '' AFTER target_ref`, + `ALTER TABLE plans ADD COLUMN IF NOT EXISTS start_period INT NOT NULL DEFAULT 0 AFTER crop_id`, + `ALTER TABLE plans ADD COLUMN IF NOT EXISTS harvest_period INT NOT NULL DEFAULT 0 AFTER start_day`, + `UPDATE plans SET start_period = start_month - 1 WHERE start_period = 0 AND start_month <> 1`, + `UPDATE plans SET harvest_period = start_period + (CASE WHEN harvest_month >= start_month THEN harvest_month - start_month ELSE harvest_month + 12 - start_month END) WHERE harvest_period = 0`, + `ALTER TABLE custom_tasks ADD COLUMN IF NOT EXISTS task_period INT NOT NULL DEFAULT 0 AFTER title`, + `UPDATE custom_tasks SET task_period = (year_offset * 12) + (month - 1) WHERE task_period = 0 AND (year_offset <> 0 OR month <> 1)`, } for _, stmt := range stmts { if _, err := db.Exec(stmt); err != nil { @@ -118,8 +130,8 @@ func ensureSchema(db *sql.DB) error { func (a *App) getSettings() (Settings, error) { var s Settings - err := a.db.QueryRow(`SELECT days_per_month,current_month,current_day FROM settings WHERE id=1`). - Scan(&s.DaysPerMonth, &s.CurrentMonth, &s.CurrentDay) + err := a.db.QueryRow(`SELECT days_per_month,current_month,current_cycle,current_day FROM settings WHERE id=1`). + Scan(&s.DaysPerMonth, &s.CurrentMonth, &s.CurrentCycle, &s.CurrentDay) return s, err } @@ -199,10 +211,10 @@ func (a *App) listProducts() ([]Product, error) { func (a *App) listPlans() ([]Plan, error) { rows, err := a.db.Query(` - SELECT p.id,p.field_id,COALESCE(p.target_ref,''),COALESCE(p.target_name,''),p.crop_id,COALESCE(c.name,''),COALESCE(c.grow_months,1),p.start_month,p.start_day,p.harvest_month,p.harvest_day,COALESCE(p.notes,''),COALESCE(c.regrow_enabled,0),COALESCE(c.regrow_cycles,0) + SELECT p.id,p.field_id,COALESCE(p.target_ref,''),COALESCE(p.target_name,''),p.crop_id,COALESCE(c.name,''),COALESCE(c.grow_months,1),p.start_period,p.start_month,p.start_day,p.harvest_period,p.harvest_month,p.harvest_day,COALESCE(p.notes,''),COALESCE(c.regrow_enabled,0),COALESCE(c.regrow_cycles,0) FROM plans p JOIN crops c ON c.id=p.crop_id - ORDER BY p.start_month,p.start_day,p.id DESC`) + ORDER BY p.start_period,p.start_day,p.id DESC`) if err != nil { return nil, err } @@ -210,9 +222,11 @@ func (a *App) listPlans() ([]Plan, error) { var out []Plan for rows.Next() { var p Plan - if err := rows.Scan(&p.ID, &p.FieldID, &p.TargetRef, &p.TargetName, &p.CropID, &p.CropName, &p.GrowMonths, &p.StartMonth, &p.StartDay, &p.HarvestMonth, &p.HarvestDay, &p.Notes, &p.RegrowEnabled, &p.RegrowCycles); err != nil { + if err := rows.Scan(&p.ID, &p.FieldID, &p.TargetRef, &p.TargetName, &p.CropID, &p.CropName, &p.GrowMonths, &p.StartPeriod, &p.StartMonth, &p.StartDay, &p.HarvestPeriod, &p.HarvestMonth, &p.HarvestDay, &p.Notes, &p.RegrowEnabled, &p.RegrowCycles); err != nil { return nil, err } + p.StartCycle = periodCycle(p.StartPeriod) + p.HarvestCycle = periodCycle(p.HarvestPeriod) out = append(out, p) } return out, rows.Err() @@ -272,9 +286,9 @@ func (a *App) listCustomTaskTemplates() ([]CustomTaskTemplate, error) { func (a *App) listCustomTasks() ([]CustomTask, error) { rows, err := a.db.Query(` - SELECT id,template_id,title,month,day,year_offset,COALESCE(target_name,''),COALESCE(notes,'') + SELECT id,template_id,title,task_period,month,day,year_offset,COALESCE(target_name,''),COALESCE(notes,'') FROM custom_tasks - ORDER BY year_offset, month, day, title`) + ORDER BY task_period, day, title`) if err != nil { return nil, err } @@ -283,9 +297,11 @@ func (a *App) listCustomTasks() ([]CustomTask, error) { var out []CustomTask for rows.Next() { var t CustomTask - if err := rows.Scan(&t.ID, &t.TemplateID, &t.Title, &t.Month, &t.Day, &t.YearOffset, &t.TargetName, &t.Notes); err != nil { + if err := rows.Scan(&t.ID, &t.TemplateID, &t.Title, &t.TaskPeriod, &t.Month, &t.Day, &t.YearOffset, &t.TargetName, &t.Notes); err != nil { return nil, err } + t.Month = periodMonth(t.TaskPeriod) + t.Cycle = periodCycle(t.TaskPeriod) out = append(out, t) } return out, rows.Err() diff --git a/cmd/server/domain.go b/cmd/server/domain.go index a5d8d50..9afa95e 100644 --- a/cmd/server/domain.go +++ b/cmd/server/domain.go @@ -90,6 +90,20 @@ func monthOptions() []MonthOption { return out } +func cycleOffsetOptions(maxOffset int) []CycleOption { + if maxOffset < 0 { + maxOffset = 0 + } + out := make([]CycleOption, 0, maxOffset+1) + for i := 0; i <= maxOffset; i++ { + out = append(out, CycleOption{ + Value: i, + Label: fmt.Sprintf("+%d Zyklus", i), + }) + } + return out +} + func monthInWindow(month, start, end int) bool { if start <= end { return month >= start && month <= end @@ -105,6 +119,14 @@ func wrapMonth(v int) int { return m } +func periodMonth(period int) int { + return (period % 12) + 1 +} + +func periodCycle(period int) int { + return period / 12 +} + func validateCropInput(name string, start, end, grow, regrowCycles int) error { if name == "" { return errors.New("Name der Feldfrucht fehlt") diff --git a/cmd/server/handlers_actions.go b/cmd/server/handlers_actions.go index 835dd0c..ba0895d 100644 --- a/cmd/server/handlers_actions.go +++ b/cmd/server/handlers_actions.go @@ -46,12 +46,13 @@ func (a *App) handleSetCurrentTime(w http.ResponseWriter, r *http.Request) { return } month := mustInt(r.FormValue("current_month"), 1) + cycle := mustInt(r.FormValue("current_cycle"), settings.CurrentCycle) day := mustInt(r.FormValue("current_day"), 1) - if month < 1 || month > 12 || day < 1 || day > settings.DaysPerMonth { + if month < 1 || month > 12 || cycle < 0 || day < 1 || day > settings.DaysPerMonth { redirectWithMessage(w, r, "/", "error", "Ingame-Zeit ungültig") return } - if _, err := a.db.Exec(`UPDATE settings SET current_month=?, current_day=? WHERE id=1`, month, day); err != nil { + if _, err := a.db.Exec(`UPDATE settings SET current_month=?, current_cycle=?, current_day=? WHERE id=1`, month, cycle, day); err != nil { redirectWithMessage(w, r, "/", "error", "Ingame-Zeit nicht gespeichert") return } @@ -369,6 +370,7 @@ func (a *App) handleCreatePlan(w http.ResponseWriter, r *http.Request) { targetRef := strings.TrimSpace(r.FormValue("target_ref")) cropID := mustInt64(r.FormValue("crop_id"), 0) startMonth := mustInt(r.FormValue("start_month"), 1) + cycleOffset := mustInt(r.FormValue("cycle_offset"), 0) startDay := mustInt(r.FormValue("start_day"), 1) notes := strings.TrimSpace(r.FormValue("notes")) if targetRef == "" || cropID <= 0 { @@ -381,7 +383,7 @@ func (a *App) handleCreatePlan(w http.ResponseWriter, r *http.Request) { redirectWithMessage(w, r, "/planning", "error", "Einstellungen nicht lesbar") return } - if startMonth < 1 || startMonth > 12 || startDay < 1 || startDay > settings.DaysPerMonth { + if startMonth < 1 || startMonth > 12 || cycleOffset < 0 || cycleOffset > 20 || startDay < 1 || startDay > settings.DaysPerMonth { redirectWithMessage(w, r, "/planning", "error", "Startdatum ungültig") return } @@ -404,11 +406,13 @@ func (a *App) handleCreatePlan(w http.ResponseWriter, r *http.Request) { return } - harvestMonth := wrapMonth(startMonth + c.GrowMonths) + startPeriod := ((settings.CurrentCycle + cycleOffset) * 12) + (startMonth - 1) + harvestPeriod := startPeriod + c.GrowMonths + harvestMonth := periodMonth(harvestPeriod) harvestDay := startDay _, err = a.db.Exec( - `INSERT INTO plans(field_id,target_ref,target_name,crop_id,start_month,start_day,harvest_month,harvest_day,notes) VALUES (?,?,?,?,?,?,?,?,?)`, - fieldID, targetRef, targetName, cropID, startMonth, startDay, harvestMonth, harvestDay, notes, + `INSERT INTO plans(field_id,target_ref,target_name,crop_id,start_period,start_month,start_day,harvest_period,harvest_month,harvest_day,notes) VALUES (?,?,?,?,?,?,?,?,?,?,?)`, + fieldID, targetRef, targetName, cropID, startPeriod, startMonth, startDay, harvestPeriod, harvestMonth, harvestDay, notes, ) if err != nil { redirectWithMessage(w, r, "/planning", "error", "Plan nicht gespeichert") @@ -508,7 +512,7 @@ func (a *App) handleCreateCustomTask(w http.ResponseWriter, r *http.Request) { title := strings.TrimSpace(r.FormValue("title")) month := mustInt(r.FormValue("month"), 0) day := mustInt(r.FormValue("day"), 0) - yearOffset := mustInt(r.FormValue("year_offset"), 0) + cycleOffset := mustInt(r.FormValue("cycle_offset"), 0) targetName := strings.TrimSpace(r.FormValue("target_name")) notes := strings.TrimSpace(r.FormValue("notes")) settings, err := a.getSettings() @@ -516,7 +520,7 @@ func (a *App) handleCreateCustomTask(w http.ResponseWriter, r *http.Request) { redirectWithMessage(w, r, "/planning", "error", "Einstellungen nicht lesbar") return } - if month < 1 || month > 12 || day < 1 || day > settings.DaysPerMonth || yearOffset < 0 || yearOffset > 4 { + if month < 1 || month > 12 || day < 1 || day > settings.DaysPerMonth || cycleOffset < 0 || cycleOffset > 20 { redirectWithMessage(w, r, "/planning", "error", "Aufgaben-Datum ungültig") return } @@ -531,8 +535,9 @@ func (a *App) handleCreateCustomTask(w http.ResponseWriter, r *http.Request) { return } - if _, err = a.db.Exec(`INSERT INTO custom_tasks(template_id,title,month,day,year_offset,target_name,notes) VALUES (?,?,?,?,?,?,?)`, - nullInt64(templateID), title, month, day, yearOffset, targetName, notes); err != nil { + taskPeriod := ((settings.CurrentCycle + cycleOffset) * 12) + (month - 1) + if _, err = a.db.Exec(`INSERT INTO custom_tasks(template_id,title,task_period,month,day,year_offset,target_name,notes) VALUES (?,?,?,?,?,?,?,?)`, + nullInt64(templateID), title, taskPeriod, month, day, cycleOffset, targetName, notes); err != nil { redirectWithMessage(w, r, "/planning", "error", "Aufgabe konnte nicht gespeichert werden") return } diff --git a/cmd/server/handlers_pages.go b/cmd/server/handlers_pages.go index ef1dfe3..4e43f75 100644 --- a/cmd/server/handlers_pages.go +++ b/cmd/server/handlers_pages.go @@ -64,8 +64,8 @@ func (a *App) handleDashboard(w http.ResponseWriter, r *http.Request) { }, Settings: settings, CurrentMonth: monthNames[settings.CurrentMonth-1], - TodayTasks: buildTasksForDay(plans, crops, products, stepMap, customTasks, doneMap, settings.CurrentMonth, settings.CurrentDay), - Calendar: buildCalendar(plans, crops, products, stepMap, customTasks, doneMap, settings.CurrentMonth, settings.CurrentDay, settings.DaysPerMonth, 14), + TodayTasks: buildTasksForDay(plans, crops, products, stepMap, customTasks, doneMap, (settings.CurrentCycle*12)+(settings.CurrentMonth-1), settings.CurrentDay), + Calendar: buildCalendar(plans, crops, products, stepMap, customTasks, doneMap, (settings.CurrentCycle*12)+(settings.CurrentMonth-1), settings.CurrentDay, settings.DaysPerMonth, 14), PlanningCount: len(plans), } data.TodayGroups = groupTasksByField(data.TodayTasks) @@ -170,6 +170,7 @@ func (a *App) handlePlanningPage(w http.ResponseWriter, r *http.Request) { }, Settings: settings, Months: monthOptions(), + CycleOffsets: cycleOffsetOptions(8), Crops: crops, Plans: plans, PlanningTargets: buildPlanningTargets(fields), diff --git a/cmd/server/main.go b/cmd/server/main.go index 1de5076..c55411c 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,4 +1,4 @@ -package main +package main import ( "database/sql" @@ -99,3 +99,4 @@ func withLogging(next http.Handler) http.Handler { log.Printf("%s %s %s", r.Method, r.URL.Path, time.Since(start).Round(time.Millisecond)) }) } + diff --git a/cmd/server/types.go b/cmd/server/types.go index 6601e54..a7017ff 100644 --- a/cmd/server/types.go +++ b/cmd/server/types.go @@ -5,6 +5,7 @@ import "database/sql" type Settings struct { DaysPerMonth int CurrentMonth int + CurrentCycle int CurrentDay int } @@ -48,10 +49,14 @@ type Plan struct { CropID int64 CropName string GrowMonths int + StartPeriod int StartMonth int StartDay int + StartCycle int + HarvestPeriod int HarvestMonth int HarvestDay int + HarvestCycle int Notes string RegrowEnabled bool RegrowCycles int @@ -75,9 +80,11 @@ type CustomTask struct { ID int64 TemplateID sql.NullInt64 Title string + TaskPeriod int Month int Day int YearOffset int + Cycle int TargetName string Notes string } @@ -104,6 +111,11 @@ type MonthOption struct { Label string } +type CycleOption struct { + Value int + Label string +} + type CalendarDay struct { Day int Tasks []Task @@ -156,6 +168,7 @@ type PlanningPage struct { BasePage Settings Settings Months []MonthOption + CycleOffsets []CycleOption Crops []Crop Plans []Plan PlanningTargets []PlanningTarget diff --git a/templates/dashboard.html b/templates/dashboard.html index df09c77..5608ae7 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -1,4 +1,4 @@ - + @@ -24,7 +24,7 @@

Aktuelle Ingame-Zeit

-

{{.CurrentMonth}} Tag {{.Settings.CurrentDay}} bei {{.Settings.DaysPerMonth}} Tagen pro Monat.

+

{{.CurrentMonth}} Tag {{.Settings.CurrentDay}} im Zyklus {{.Settings.CurrentCycle}} bei {{.Settings.DaysPerMonth}} Tagen pro Monat.

{{.PlanningCount}} Plan-Einträge insgesamt.

+ diff --git a/templates/planning.html b/templates/planning.html index b566c64..f77fb60 100644 --- a/templates/planning.html +++ b/templates/planning.html @@ -1,4 +1,4 @@ - + @@ -44,6 +44,13 @@ {{end}} + @@ -88,8 +95,12 @@ -