slots basic info
This commit is contained in:
@ -60,6 +60,7 @@ public class DoneController extends CommonController {
|
|||||||
model.addAttribute("sum", sumBean);
|
model.addAttribute("sum", sumBean);
|
||||||
model.addAttribute("daysum", doneService.getDaysum(day, username));
|
model.addAttribute("daysum", doneService.getDaysum(day, username));
|
||||||
model.addAttribute("overtimeBean", doneService.getOvertimeBean(username));
|
model.addAttribute("overtimeBean", doneService.getOvertimeBean(username));
|
||||||
|
model.addAttribute("slots", doneService.getSlots(username));
|
||||||
model.addAttribute("schedule", weekBean.toJson());
|
model.addAttribute("schedule", weekBean.toJson());
|
||||||
model.addAttribute("recentList", doneService.getListRecent(username, 10));
|
model.addAttribute("recentList", doneService.getListRecent(username, 10));
|
||||||
model.addAttribute("projectList", doneService.getProjects(false));
|
model.addAttribute("projectList", doneService.getProjects(false));
|
||||||
@ -200,4 +201,12 @@ public class DoneController extends CommonController {
|
|||||||
doneService.upsertOvertime(bean, username);
|
doneService.upsertOvertime(bean, username);
|
||||||
return "redirect:/done/list";
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,9 @@ import java.time.Duration;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
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.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@ -21,6 +24,7 @@ import org.jooq.Record3;
|
|||||||
import org.jooq.Record5;
|
import org.jooq.Record5;
|
||||||
import org.jooq.SelectConditionStep;
|
import org.jooq.SelectConditionStep;
|
||||||
import org.jooq.SelectHavingStep;
|
import org.jooq.SelectHavingStep;
|
||||||
|
import org.jooq.SelectSeekStep1;
|
||||||
import org.jooq.UpdateConditionStep;
|
import org.jooq.UpdateConditionStep;
|
||||||
import org.jooq.impl.DSL;
|
import org.jooq.impl.DSL;
|
||||||
import org.jooq.types.YearToSecond;
|
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.db.done.tables.records.TOvertimeRecord;
|
||||||
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
|
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
||||||
|
import de.jottyfan.timetrack.modules.done.model.SlotBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -71,7 +76,8 @@ public class DoneRepository {
|
|||||||
bean.setBreaks(r.get(BREAKTIME));
|
bean.setBreaks(r.get(BREAKTIME));
|
||||||
YearToSecond dayOvertime = r.get(V_DAY.DAY_OVERTIME);
|
YearToSecond dayOvertime = r.get(V_DAY.DAY_OVERTIME);
|
||||||
Duration dayOvertimeDuration = dayOvertime == null ? null : dayOvertime.toDuration();
|
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));
|
bean.setTotalOvertime(getOvertimeOf(day, login));
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
@ -149,4 +155,51 @@ public class DoneRepository {
|
|||||||
LOGGER.trace(sql);
|
LOGGER.trace(sql);
|
||||||
sql.execute();
|
sql.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SlotBean> getSlots(String login) {
|
||||||
|
SelectSeekStep1<Record3<Integer, LocalDate, Integer>, 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<Record3<Integer, LocalDate, Integer>> i = sql.fetch().iterator();
|
||||||
|
List<SlotBean> list = new ArrayList<>();
|
||||||
|
while (i.hasNext()) {
|
||||||
|
Record3<Integer, LocalDate, Integer> 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<Record3<Integer, LocalDate, Integer>> 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<Integer, LocalDate, Integer> 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.DoneBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.FavoriteBean;
|
import de.jottyfan.timetrack.modules.done.model.FavoriteBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
||||||
|
import de.jottyfan.timetrack.modules.done.model.SlotBean;
|
||||||
import de.jottyfan.timetrack.modules.note.NoteService;
|
import de.jottyfan.timetrack.modules.note.NoteService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,4 +245,12 @@ public class DoneService {
|
|||||||
public void upsertOvertime(OvertimeBean bean, String username) {
|
public void upsertOvertime(OvertimeBean bean, String username) {
|
||||||
repository.upsertOvertime(bean.getId(), username, bean.getImpact(), bean.getOvertimeMinutes());
|
repository.upsertOvertime(bean.getId(), username, bean.getImpact(), bean.getOvertimeMinutes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SlotBean> getSlots(String username) {
|
||||||
|
return repository.getSlots(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotBean getSlot(Integer id, String username) {
|
||||||
|
return repository.getSlot(id, username);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -403,3 +403,44 @@ body {
|
|||||||
.golden {
|
.golden {
|
||||||
color: darkgoldenrod;
|
color: darkgoldenrod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
@ -244,7 +244,16 @@
|
|||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
Zur Berechnung der täglichen Überstunden müssen Slots angelegt werden, die definieren, an welchen Tagen wieviele Stunden zu arbeiten ist.
|
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.
|
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.
|
||||||
</div>
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col slot_badge" th:each="s : ${slots}">
|
||||||
|
<span class="slot_badge_left" th:text="${#temporals.format(s.day, 'EEE, dd.MM.yyyy')}"></span><a th:href="@{/done/slot/{id}(id=${s.id})}" class="slot_badge_middle"><i class="fas fa-pencil"></i></a><span class="slot_badge_right" th:text="${s.printTime()}"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
TODO: nur die Slots dieses Monats anzeigen, damit die Ladezeit nicht unnötig belastet wird
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
23
src/main/resources/templates/done/slot/item.html
Normal file
23
src/main/resources/templates/done/slot/item.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||||
|
<head>
|
||||||
|
<title>Slot aktualisieren</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ul layout:fragment="menu">
|
||||||
|
</ul>
|
||||||
|
<main layout:fragment="content">
|
||||||
|
<div class="container formpane">
|
||||||
|
<div class="row" th:if="${bean}">
|
||||||
|
<div class="col-sm-3">ID</div>
|
||||||
|
<div class="col-sm-9" th:text="${bean.id}"></div>
|
||||||
|
<div class="col-sm-3">Tag</div>
|
||||||
|
<div class="col-sm-9" th:text="${#temporals.format(bean.day, 'EEEE, dd.MM.yyyy')}"></div>
|
||||||
|
<div class="col-sm-3">vereinbarte Arbeitszeit</div>
|
||||||
|
<div class="col-sm-9" th:text="${bean.printTime()}"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
Reference in New Issue
Block a user