From 568dfc8a6449b5f52715f93e27beb7766f7e89f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Henke?= Date: Thu, 4 Jan 2024 21:53:13 +0100 Subject: [PATCH] slots basic info --- .../modules/done/DoneController.java | 9 +++ .../modules/done/DoneRepository.java | 59 +++++++++++++- .../timetrack/modules/done/DoneService.java | 9 +++ .../modules/done/model/SlotBean.java | 79 +++++++++++++++++++ src/main/resources/static/css/style.css | 43 +++++++++- src/main/resources/templates/done/list.html | 9 +++ .../resources/templates/done/slot/item.html | 23 ++++++ 7 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 src/main/java/de/jottyfan/timetrack/modules/done/model/SlotBean.java create mode 100644 src/main/resources/templates/done/slot/item.html diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java b/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java index 84b5a41..bcfb5dd 100644 --- a/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java +++ b/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java @@ -60,6 +60,7 @@ public class DoneController extends CommonController { model.addAttribute("sum", sumBean); model.addAttribute("daysum", doneService.getDaysum(day, username)); model.addAttribute("overtimeBean", doneService.getOvertimeBean(username)); + model.addAttribute("slots", doneService.getSlots(username)); model.addAttribute("schedule", weekBean.toJson()); model.addAttribute("recentList", doneService.getListRecent(username, 10)); model.addAttribute("projectList", doneService.getProjects(false)); @@ -200,4 +201,12 @@ public class DoneController extends CommonController { doneService.upsertOvertime(bean, username); return "redirect:/done/list"; } + + @RolesAllowed("timetrack_user") + @GetMapping("/done/slot/{id}") + public String loadSlot(@PathVariable("id") Integer id, Model model) { + String username = provider.getName(); + model.addAttribute("bean", doneService.getSlot(id, username)); + return "/done/slot/item"; + } } diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java b/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java index 4974d86..4a1ec57 100644 --- a/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java +++ b/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java @@ -9,6 +9,9 @@ import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -21,6 +24,7 @@ import org.jooq.Record3; import org.jooq.Record5; import org.jooq.SelectConditionStep; import org.jooq.SelectHavingStep; +import org.jooq.SelectSeekStep1; import org.jooq.UpdateConditionStep; import org.jooq.impl.DSL; import org.jooq.types.YearToSecond; @@ -30,6 +34,7 @@ import org.springframework.stereotype.Repository; import de.jottyfan.timetrack.db.done.tables.records.TOvertimeRecord; import de.jottyfan.timetrack.modules.done.model.DaysumBean; import de.jottyfan.timetrack.modules.done.model.OvertimeBean; +import de.jottyfan.timetrack.modules.done.model.SlotBean; /** * @@ -46,7 +51,7 @@ public class DoneRepository { public DaysumBean getDaysum(LocalDate day, String login) { Field WORKTIME = DSL.field("worktime", LocalTime.class); Field BREAKTIME = DSL.field("breaktime", LocalTime.class); - + SelectConditionStep> sql = jooq // @formatter:off .select(V_DAY.STARTTIME, @@ -71,12 +76,13 @@ public class DoneRepository { bean.setBreaks(r.get(BREAKTIME)); YearToSecond dayOvertime = r.get(V_DAY.DAY_OVERTIME); Duration dayOvertimeDuration = dayOvertime == null ? null : dayOvertime.toDuration(); - bean.setDayOvertime(dayOvertimeDuration == null ? null : Long.valueOf(dayOvertimeDuration.toMinutes()).intValue()); + bean.setDayOvertime( + dayOvertimeDuration == null ? null : Long.valueOf(dayOvertimeDuration.toMinutes()).intValue()); bean.setTotalOvertime(getOvertimeOf(day, login)); return bean; } } - + private Integer getOvertimeOf(LocalDate day, String login) { Field OVERTIME = DSL.field("overtime", Integer.class); SelectHavingStep> sql = jooq @@ -149,4 +155,51 @@ public class DoneRepository { LOGGER.trace(sql); sql.execute(); } + + public List getSlots(String login) { + SelectSeekStep1, LocalDate> sql = jooq + // @formatter:off + .select(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME, + T_REQUIRED_WORKTIME.DAY, + T_REQUIRED_WORKTIME.REQUIRED_MINUTES) + .from(T_REQUIRED_WORKTIME) + .innerJoin(T_LOGIN).on(T_LOGIN.PK.eq(T_REQUIRED_WORKTIME.FK_LOGIN)) + .where(T_LOGIN.LOGIN.eq(login)) + .orderBy(T_REQUIRED_WORKTIME.DAY); + // @formatter:on + LOGGER.trace(sql); + Iterator> i = sql.fetch().iterator(); + List list = new ArrayList<>(); + while (i.hasNext()) { + Record3 n = i.next(); + list.add(SlotBean.of(n.get(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME), n.get(T_REQUIRED_WORKTIME.DAY), + n.get(T_REQUIRED_WORKTIME.REQUIRED_MINUTES))); + } + return list; + } + + /** + * get slot if login fits + * + * @param id the ID of the slot + * @param login the login + * @return the slot or null + */ + public SlotBean getSlot(Integer id, String login) { + SelectConditionStep> sql = jooq + // @formatter:off + .select(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME, + T_REQUIRED_WORKTIME.DAY, + T_REQUIRED_WORKTIME.REQUIRED_MINUTES) + .from(T_REQUIRED_WORKTIME) + .innerJoin(T_LOGIN).on(T_LOGIN.PK.eq(T_REQUIRED_WORKTIME.FK_LOGIN)) + .where(T_LOGIN.LOGIN.eq(login)) + .and(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME.eq(id)); + // @formatter:on + LOGGER.trace(sql); + Record3 r = sql.fetchOne(); + return r == null ? null + : SlotBean.of(r.get(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME), r.get(T_REQUIRED_WORKTIME.DAY), + r.get(T_REQUIRED_WORKTIME.REQUIRED_MINUTES)); + } } diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java b/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java index 795b6d4..88bca5e 100644 --- a/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java +++ b/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java @@ -23,6 +23,7 @@ import de.jottyfan.timetrack.modules.done.model.DaysumBean; import de.jottyfan.timetrack.modules.done.model.DoneBean; import de.jottyfan.timetrack.modules.done.model.FavoriteBean; import de.jottyfan.timetrack.modules.done.model.OvertimeBean; +import de.jottyfan.timetrack.modules.done.model.SlotBean; import de.jottyfan.timetrack.modules.note.NoteService; /** @@ -244,4 +245,12 @@ public class DoneService { public void upsertOvertime(OvertimeBean bean, String username) { repository.upsertOvertime(bean.getId(), username, bean.getImpact(), bean.getOvertimeMinutes()); } + + public List getSlots(String username) { + return repository.getSlots(username); + } + + public SlotBean getSlot(Integer id, String username) { + return repository.getSlot(id, username); + } } diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/model/SlotBean.java b/src/main/java/de/jottyfan/timetrack/modules/done/model/SlotBean.java new file mode 100644 index 0000000..7965495 --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/modules/done/model/SlotBean.java @@ -0,0 +1,79 @@ +package de.jottyfan.timetrack.modules.done.model; + +import java.io.Serializable; +import java.time.LocalDate; + +/** + * + * @author jotty + * + */ +public class SlotBean implements Serializable { + private static final long serialVersionUID = 1L; + + private Integer id; + private LocalDate day; + private Integer minutes; + + public static final SlotBean of(Integer id, LocalDate day, Integer minutes) { + SlotBean bean = new SlotBean(); + bean.setId(id); + bean.setDay(day); + bean.setMinutes(minutes); + return bean; + } + + public String printTime() { + Integer hours = 0; + Integer mins = 0; + if (minutes != null) { + hours = minutes / 60; + mins = minutes % 60; + } + return String.format("%2d:%02d", hours, mins); + } + + /** + * @return the day + */ + public LocalDate getDay() { + return day; + } + + /** + * @param day the day to set + */ + public void setDay(LocalDate day) { + this.day = day; + } + + /** + * @return the minutes + */ + public Integer getMinutes() { + return minutes; + } + + /** + * @param minutes the minutes to set + */ + public void setMinutes(Integer minutes) { + this.minutes = minutes; + } + + /** + * @return the id + */ + public Integer getId() { + return id; + } + + /** + * @param id the id to set + */ + public void setId(Integer id) { + this.id = id; + } + + +} diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css index b914b1a..3e82177 100644 --- a/src/main/resources/static/css/style.css +++ b/src/main/resources/static/css/style.css @@ -402,4 +402,45 @@ body { .golden { color: darkgoldenrod; -} \ No newline at end of file +} + +.slot_badge { + white-space: nowrap; + margin-bottom: 2px; +} + +.slot_badge_left { + border: 1px solid silver; + border-radius: 12px 0px 0px 12px; + background-color: #ccc; + color: black; + padding-left: 2px; +} + +[data-bs-theme=dark] .slot_badge_left { + background-color: gray; +} + +.slot_badge_middle { + border-top: 1px solid silver; + border-bottom: 1px solid silver; + padding-left: 2px; + padding-right: 2px; +} + +.slot_badge_middle:hover { + color: white; + background-image: linear-gradient(to right bottom, #99c1f1, #1a5f64); +} + +.slot_badge_right { + border: 1px solid silver; + border-radius: 0px 12px 12px 0px; + background-color: transparent; + color: black; + padding-right: 2px; +} + +[data-bs-theme=dark] .slot_badge_right { + color: white; +} diff --git a/src/main/resources/templates/done/list.html b/src/main/resources/templates/done/list.html index 68d800d..d28139f 100644 --- a/src/main/resources/templates/done/list.html +++ b/src/main/resources/templates/done/list.html @@ -244,7 +244,16 @@
Zur Berechnung der täglichen Überstunden müssen Slots angelegt werden, die definieren, an welchen Tagen wieviele Stunden zu arbeiten ist. Urlaub und Arbeitsbefreiung können durch das Entfernen des jeweiligen Slots ermöglicht werden. + Die Überstundenberechnung hängt von der Vollständigkeit der vorhandenen Slots ab; fehlen Slots, wird die Arbeitszeit jener Tage nicht eingerechnet.
+
+
+
+ +
+
+
+ TODO: nur die Slots dieses Monats anzeigen, damit die Ladezeit nicht unnötig belastet wird