project management

This commit is contained in:
Jörg Henke
2026-01-15 16:22:54 +01:00
parent f8290cdbb6
commit aaee7c9dff
10 changed files with 360 additions and 103 deletions

View File

@@ -28,7 +28,7 @@ public class ProjectmanagementController extends CommonController {
@RolesAllowed("timetrack_user") @RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement") @GetMapping("/projectmanagement")
public String getDashboard(final Model model) { public String getDashboard(final Model model) {
model.addAttribute("projects", service.getProjects()); model.addAttribute("projects", service.getProjects(true));
return "/projectmanagement/dashboard"; return "/projectmanagement/dashboard";
} }
@@ -36,7 +36,16 @@ public class ProjectmanagementController extends CommonController {
@GetMapping("/projectmanagement/project/add") @GetMapping("/projectmanagement/project/add")
public String getProjectAddMask(final Model model) { public String getProjectAddMask(final Model model) {
model.addAttribute("bean", new ProjectBean()); model.addAttribute("bean", new ProjectBean());
return "/projectmanagement/project/add"; model.addAttribute("funders", service.getFunders());
return "/projectmanagement/project/item";
}
@RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement/project/{pkProject}/edit")
public String getProjectAddMask(@PathVariable("pkProject") Integer pkProject, final Model model) {
model.addAttribute("bean", service.getProject(pkProject));
model.addAttribute("funders", service.getFunders());
return "/projectmanagement/project/item";
} }
@RolesAllowed("timetrack_user") @RolesAllowed("timetrack_user")
@@ -46,6 +55,20 @@ public class ProjectmanagementController extends CommonController {
return "/projectmanagement/workpackage/item"; return "/projectmanagement/workpackage/item";
} }
@RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement/workpackage/{pkWorkpackage}/delete")
public String deleteWorkpackage(@PathVariable("pkWorkpackage") Integer pkWorkpackage) {
service.deleteWorkpackage(pkWorkpackage);
return "redirect:/projectmanagement";
}
@RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement/{pkProject}/delete")
public String deleteProject(@PathVariable("pkProject") Integer pkProject) {
service.deleteProject(pkProject);
return "redirect:/projectmanagement";
}
@RolesAllowed("timetrack_user") @RolesAllowed("timetrack_user")
@GetMapping("/projectmanagement/project/{fkProject}/addWorkpackage") @GetMapping("/projectmanagement/project/{fkProject}/addWorkpackage")
public String getWorkpackageAddMask(@PathVariable("fkProject") Integer fkProject, final Model model) { public String getWorkpackageAddMask(@PathVariable("fkProject") Integer fkProject, final Model model) {
@@ -54,14 +77,28 @@ public class ProjectmanagementController extends CommonController {
} }
@RolesAllowed("timetrack_user") @RolesAllowed("timetrack_user")
@PostMapping("/projectmanagement/project/{fkProject}/update") @PostMapping("/projectmanagement/upsert")
public String upsertWorkpackage(@ModelAttribute("bean") ProjectBean bean, BindingResult bindingResult, final Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("error", bindingResult.getAllErrors().toString());
return "/projectmanagement";
}
service.upsertProject(bean);
return "redirect:/projectmanagement";
}
@RolesAllowed("timetrack_user")
@PostMapping("/projectmanagement/project/{fkProject}/upsert")
public String updateWorkpackage(@PathVariable("fkProject") Integer fkProject, public String updateWorkpackage(@PathVariable("fkProject") Integer fkProject,
@ModelAttribute("bean") WorkpackageBean bean, BindingResult bindingResult, final Model model) { @ModelAttribute("bean") WorkpackageBean bean, BindingResult bindingResult, final Model model) {
if (bindingResult.hasErrors()) { if (bindingResult.hasErrors()) {
model.addAttribute("error", bindingResult.getAllErrors().toString());
return "/projectmanagement/workpackage/item"; return "/projectmanagement/workpackage/item";
} }
bean.setFkProject(fkProject); bean.setFkProject(fkProject);
service.updateWorkpackage(bean); service.upsertWorkpackage(bean);
return "redirect:/projectmanagement"; return "redirect:/projectmanagement";
} }
} }

View File

@@ -1,18 +1,23 @@
package de.jottyfan.timetrack.modules.projectmanagement; package de.jottyfan.timetrack.modules.projectmanagement;
import static de.jottyfan.timetrack.db.project.Tables.T_FUNDER;
import static de.jottyfan.timetrack.db.project.Tables.T_PROJECT; import static de.jottyfan.timetrack.db.project.Tables.T_PROJECT;
import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE; import static de.jottyfan.timetrack.db.project.Tables.T_WORKPACKAGE;
import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jooq.DSLContext; import org.jooq.DSLContext;
import org.jooq.InsertValuesStep3;
import org.jooq.InsertValuesStep6;
import org.jooq.UpdateConditionStep; import org.jooq.UpdateConditionStep;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import de.jottyfan.timetrack.db.project.tables.records.TFunderRecord;
import de.jottyfan.timetrack.db.project.tables.records.TProjectRecord; import de.jottyfan.timetrack.db.project.tables.records.TProjectRecord;
import de.jottyfan.timetrack.db.project.tables.records.TWorkpackageRecord; import de.jottyfan.timetrack.db.project.tables.records.TWorkpackageRecord;
import de.jottyfan.timetrack.modules.projectmanagement.model.ProjectBean; import de.jottyfan.timetrack.modules.projectmanagement.model.ProjectBean;
@@ -29,6 +34,10 @@ public class ProjectmanagementRepository {
@Autowired @Autowired
private DSLContext jooq; private DSLContext jooq;
public List<TFunderRecord> getFunders() {
return jooq.selectFrom(T_FUNDER).fetchInto(TFunderRecord.class);
}
public List<ProjectBean> getProjects() { public List<ProjectBean> getProjects() {
List<TProjectRecord> projects = jooq.selectFrom(T_PROJECT).fetchInto(TProjectRecord.class); List<TProjectRecord> projects = jooq.selectFrom(T_PROJECT).fetchInto(TProjectRecord.class);
List<TWorkpackageRecord> workpackages = jooq.selectFrom(T_WORKPACKAGE).fetchInto(TWorkpackageRecord.class); List<TWorkpackageRecord> workpackages = jooq.selectFrom(T_WORKPACKAGE).fetchInto(TWorkpackageRecord.class);
@@ -49,7 +58,8 @@ public class ProjectmanagementRepository {
} }
public WorkpackageBean getWorkpackage(Integer pkWorkpackage) { public WorkpackageBean getWorkpackage(Integer pkWorkpackage) {
return jooq.selectFrom(T_WORKPACKAGE).where(T_WORKPACKAGE.PK_WORKPACKAGE.eq(pkWorkpackage)).fetchOneInto(WorkpackageBean.class); return jooq.selectFrom(T_WORKPACKAGE).where(T_WORKPACKAGE.PK_WORKPACKAGE.eq(pkWorkpackage))
.fetchOneInto(WorkpackageBean.class);
} }
public void updateWorkpackage(WorkpackageBean bean) { public void updateWorkpackage(WorkpackageBean bean) {
@@ -67,4 +77,54 @@ public class ProjectmanagementRepository {
sql.execute(); sql.execute();
} }
public void insertWorkpackage(WorkpackageBean bean) {
InsertValuesStep6<TWorkpackageRecord, Integer, String, String, String, String, LocalDate> sql = jooq
// @formatter:off
.insertInto(T_WORKPACKAGE,
T_WORKPACKAGE.FK_PROJECT,
T_WORKPACKAGE.NAME,
T_WORKPACKAGE.DESCRIPTION,
T_WORKPACKAGE.MILESTONE_URL,
T_WORKPACKAGE.CONTRACT_URL,
T_WORKPACKAGE.PLANNED_DUEDATE)
.values(bean.getFkProject(), bean.getName(), bean.getDescription(), bean.getMilestoneUrl(), bean.getContractUrl(), bean.getPlannedDuedate());
// @formatter:on
sql.execute();
}
public void deleteWorkpackage(Integer pkWorkpackage) {
jooq.deleteFrom(T_WORKPACKAGE).where(T_WORKPACKAGE.PK_WORKPACKAGE.eq(pkWorkpackage)).execute();
}
public void updateProject(ProjectBean bean) {
UpdateConditionStep<TProjectRecord> sql = jooq
// @formatter:off
.update(T_PROJECT)
.set(T_PROJECT.FK_FUNDER, bean.getFkFunder())
.set(T_PROJECT.NAME, bean.getName())
.set(T_PROJECT.DESCRIPTION, bean.getDescription())
.where(T_PROJECT.PK_PROJECT.eq(bean.getPkProject()));
// @formatter:on
sql.execute();
}
public void insertProject(ProjectBean bean) {
InsertValuesStep3<TProjectRecord, String, String, Integer> sql = jooq
// @formatter:off
.insertInto(T_PROJECT,
T_PROJECT.NAME,
T_PROJECT.DESCRIPTION,
T_PROJECT.FK_FUNDER)
.values(bean.getName(), bean.getDescription(), bean.getFkFunder());
// @formatter:on
sql.execute();
}
public void deleteProject(Integer pkProject) {
jooq.deleteFrom(T_PROJECT).where(T_PROJECT.PK_PROJECT.eq(pkProject)).execute();
}
public ProjectBean getProject(Integer pkProject) {
return jooq.selectFrom(T_PROJECT).where(T_PROJECT.PK_PROJECT.eq(pkProject)).fetchOneInto(ProjectBean.class);
}
} }

View File

@@ -1,10 +1,13 @@
package de.jottyfan.timetrack.modules.projectmanagement; package de.jottyfan.timetrack.modules.projectmanagement;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import de.jottyfan.timetrack.db.project.tables.records.TFunderRecord;
import de.jottyfan.timetrack.modules.projectmanagement.model.ProjectBean; import de.jottyfan.timetrack.modules.projectmanagement.model.ProjectBean;
import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean; import de.jottyfan.timetrack.modules.projectmanagement.model.WorkpackageBean;
@@ -24,8 +27,17 @@ public class ProjectmanagementService {
* *
* @return all projects * @return all projects
*/ */
public List<ProjectBean> getProjects() { public List<ProjectBean> getProjects(boolean includeFunderName) {
return repository.getProjects(); List<ProjectBean> list = repository.getProjects();
if (includeFunderName) {
List<TFunderRecord> funders = repository.getFunders();
Map<Integer, String> funderMap = new HashMap<>();
funders.forEach(f -> funderMap.put(f.getPkFunder(), f.getName()));
for (ProjectBean bean : list) {
bean.setFunderName(funderMap.get(bean.getFkFunder()));
}
}
return list;
} }
/** /**
@@ -43,7 +55,40 @@ public class ProjectmanagementService {
* *
* @param bean the bean * @param bean the bean
*/ */
public void updateWorkpackage(WorkpackageBean bean) { public void upsertWorkpackage(WorkpackageBean bean) {
if (bean.getPkWorkpackage() == null) {
repository.insertWorkpackage(bean);
} else {
repository.updateWorkpackage(bean); repository.updateWorkpackage(bean);
} }
}
/**
* delete the work package
*
* @param pkWorkpackage the ID of the work package
*/
public void deleteWorkpackage(Integer pkWorkpackage) {
repository.deleteWorkpackage(pkWorkpackage);
}
public void upsertProject(ProjectBean bean) {
if (bean.getPkProject() == null) {
repository.insertProject(bean);
} else {
repository.updateProject(bean);
}
}
public void deleteProject(Integer pkProject) {
repository.deleteProject(pkProject);
}
public List<TFunderRecord> getFunders() {
return repository.getFunders();
}
public ProjectBean getProject(Integer pkProject) {
return repository.getProject(pkProject);
}
} }

View File

@@ -17,6 +17,8 @@ public class ProjectBean implements Serializable {
private Integer pkProject; private Integer pkProject;
private String name; private String name;
private String description; private String description;
private Integer fkFunder;
private String funderName;
private final List<WorkpackageBean> workpackages; private final List<WorkpackageBean> workpackages;
public ProjectBean() { public ProjectBean() {
@@ -28,6 +30,7 @@ public class ProjectBean implements Serializable {
bean.setPkProject(r.getPkProject()); bean.setPkProject(r.getPkProject());
bean.setName(r.getName()); bean.setName(r.getName());
bean.setDescription(r.getDescription()); bean.setDescription(r.getDescription());
bean.setFkFunder(r.getFkFunder());
if (workpackages != null) { if (workpackages != null) {
bean.getWorkpackages().addAll(workpackages); bean.getWorkpackages().addAll(workpackages);
} }
@@ -82,4 +85,32 @@ public class ProjectBean implements Serializable {
public void setPkProject(Integer pkProject) { public void setPkProject(Integer pkProject) {
this.pkProject = pkProject; this.pkProject = pkProject;
} }
/**
* @return the funderName
*/
public String getFunderName() {
return funderName;
}
/**
* @param funderName the funderName to set
*/
public void setFunderName(String funderName) {
this.funderName = funderName;
}
/**
* @return the fkFunder
*/
public Integer getFkFunder() {
return fkFunder;
}
/**
* @param fkFunder the fkFunder to set
*/
public void setFkFunder(Integer fkFunder) {
this.fkFunder = fkFunder;
}
} }

View File

@@ -501,6 +501,7 @@ body {
} }
.dashboardcard { .dashboardcard {
width: 312px !important; width: 312px;
margin: 24px !important; margin: 8px;
padding: 0px;
} }

View File

@@ -13,8 +13,13 @@
<main layout:fragment="content"> <main layout:fragment="content">
<div class="container"> <div class="container">
<div class="row"> <div class="row">
<div class="col-sm-12 col-md-4 col-lg-2 card dashboardcard" th:each="p : ${projects}"> <div class="col-sm-12 col-md-3 col-lg-2 dashboardcard" th:each="p : ${projects}">
<div class="card-header" th:text="${p.name}"></div> <div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<span th:text="${p.funderName}"></span>:
<span class="fw-bold ms-auto" th:text="${p.name}"></span>
<a th:href="@{/projectmanagement/project/{p}/edit(p=${p.pkProject})}" class="btn btn-link ms-auto" title="bearbeiten">edit</a>
</div>
<div class="card-body"> <div class="card-body">
<div th:each="w : ${p.workpackages}"> <div th:each="w : ${p.workpackages}">
<a th:href="@{/projectmanagement/workpackage/{id}(id=${w.pkWorkpackage})}" th:text="${w.name}"></a> <a th:href="@{/projectmanagement/workpackage/{id}(id=${w.pkWorkpackage})}" th:text="${w.name}"></a>
@@ -25,6 +30,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</main> </main>
</body> </body>
</html> </html>

View File

@@ -1,19 +0,0 @@
<!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>Projektmanagement</title>
</head>
<body>
<font layout:fragment="title">Projekt</font>
<ul layout:fragment="menu">
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
<a class="nav-link btn btn-success btn-white-text" th:href="@{/projectmanagement}">abbrechen</a>
</li>
</ul>
<main layout:fragment="content">
<div class="container">
TODO: Maske zum Anlegen eines neuen Projektes
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,66 @@
<!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>Projektmanagement</title>
</head>
<body>
<font layout:fragment="title">Projekt</font>
<ul layout:fragment="menu">
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
<a class="nav-link btn btn-secondary btn-white-text" th:href="@{/projectmanagement}">abbrechen</a>
</li>
</ul>
<main layout:fragment="content">
<div class="container">
<div class="alert alert-danger" th:if="${error}" th:text="${error}"></div>
<form th:action="@{/projectmanagement/upsert}" method="post" th:object="${bean}">
<div class="container m-2">
<div class="row g-2">
<div class="col-2" th:if="${bean.pkProject}">ID</div>
<div class="col-10" th:if="${bean.pkProject}">
<input type="text" class="form-control" th:field="*{pkProject}" readonly="readonly" />
</div>
<div class="col-2">Name</div>
<div class="col-10">
<input type="text" class="form-control" th:field="*{name}" />
</div>
<div class="col-2">Beschreibung</div>
<div class="col-10">
<textarea class="form-control" th:field="*{description}"></textarea>
</div>
<div class="col-2">Geldgeber</div>
<div class="col-10">
<select th:field="*{fkFunder}" class="select-field">
<option value="" label="--- bitte wählen ---" />
<option th:each="f : ${funders}" th:label="${f.name}" th:value="${f.pkFunder}" />
</select>
</div>
<div class="col-2"></div>
<div class="col-5">
<input type="submit" class="btn btn-primary" value="Speichern">
</div>
<div class="col-5" th:if="${bean.pkProject}">
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">Löschen</button>
</div>
</div>
</div>
</form>
</div>
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Bestätigung für Löschvorgang</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>
</div>
<div class="modal-body">Bist du sicher, dass du dieses Element löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<a th:href="@{/projectmanagement/{p}/delete(p=${bean.pkProject})}" class="btn btn-danger">Löschen</a>
</div>
</div>
</div>
</div>
</main>
</body>
</html>

View File

@@ -7,20 +7,17 @@
<font layout:fragment="title">Workpackage</font> <font layout:fragment="title">Workpackage</font>
<ul layout:fragment="menu"> <ul layout:fragment="menu">
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"> <li class="nav-item" sec:authorize="hasRole('timetrack_user')">
<a class="nav-link btn btn-success btn-white-text" th:href="@{/projectmanagement}">abbrechen</a> <a class="nav-link btn btn-secondary btn-white-text" th:href="@{/projectmanagement}">abbrechen</a>
</li> </li>
</ul> </ul>
<main layout:fragment="content"> <main layout:fragment="content">
<div class="container"> <div class="container">
<div th:unless="${bean.pkWorkpackage}"> <div class="alert alert-danger" th:if="${error}" th:text="${error}"></div>
TODO: Maske zum Anlegen eines neuen Workpackages für Projekt <span th:text="${bean.fkProject}"></span> <form th:action="@{/projectmanagement/project/{p}/upsert(p=${bean.fkProject})}" method="post" th:object="${bean}">
</div>
<div th:if="${bean.pkWorkpackage}">
<form th:action="@{/projectmanagement/project/{p}/update(p=${bean.fkProject})}" method="post" th:object="${bean}">
<div class="container m-2"> <div class="container m-2">
<div class="row g-2"> <div class="row g-2">
<div class="col-2">ID</div> <div class="col-2" th:if="${bean.pkWorkpackage}">ID</div>
<div class="col-10"> <div class="col-10" th:if="${bean.pkWorkpackage}">
<input type="text" class="form-control" th:field="*{pkWorkpackage}" readonly="readonly" /> <input type="text" class="form-control" th:field="*{pkWorkpackage}" readonly="readonly" />
</div> </div>
<div class="col-2">Name</div> <div class="col-2">Name</div>
@@ -44,13 +41,30 @@
<input type="text" class="form-control" th:field="*{plannedDuedate}" /> <input type="text" class="form-control" th:field="*{plannedDuedate}" />
</div> </div>
<div class="col-2"></div> <div class="col-2"></div>
<div class="col-10"> <div class="col-5">
<input type="submit" class="btn btn-primary" value="Speichern"> <input type="submit" class="btn btn-primary" value="Speichern">
</div> </div>
<div class="col-5" th:if="${bean.pkWorkpackage}">
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">Löschen</button>
</div>
</div> </div>
</div> </div>
</form> </form>
</div> </div>
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Bestätigung für Löschvorgang</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Schließen"></button>
</div>
<div class="modal-body">Bist du sicher, dass du dieses Element löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<a th:href="@{/projectmanagement/workpackage/{p}/delete(p=${bean.pkWorkpackage})}" class="btn btn-danger">Löschen</a>
</div>
</div>
</div>
</div> </div>
</main> </main>
</body> </body>

View File

@@ -1,46 +1,62 @@
<!DOCTYPE html> <!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" <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}">
xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
<head> <head>
<title>Timetrack</title> <title>Timetrack</title>
</head> </head>
<body> <body>
<ul layout:fragment="menu"> <ul layout:fragment="menu">
</ul> </ul>
<main layout:fragment="content"> <main layout:fragment="content">
<div class="card dashboardcard">
<div class="card-header"><a class="btn btn-seondary btn-bordered btn-secondaryhover" style="width: 100%"
th:href="@{/done/list}">heutige Arbeitszeiten</a></div>
<div class="card-body">
<div class="container"> <div class="container">
<div class="card dashboardcard">
<div class="card-header">
<a class="btn btn-seondary btn-bordered btn-secondaryhover" style="width: 100%" th:href="@{/done/list}">heutige Arbeitszeiten</a>
</div>
<div class="card-body">
<div class="row"> <div class="row">
<div class="col-8"><span class="spanlabel">Start:</span></div> <div class="col-8">
<div class="col-4"><span class="emphgreen round-border border-frame" th:text="${sum.start}"></span></div> <span class="spanlabel">Start:</span>
<div class="col-8"><span class="spanlabel">Ende:</span></div> </div>
<div class="col-4"><span class="emphgreen round-border border-frame" th:text="${sum.end}"></span></div> <div class="col-4">
<div class="col-8"><span class="spanlabel">Arbeitszeit total:</span></div> <span class="emphgreen round-border border-frame" th:text="${sum.start}"></span>
<div class="col-4"><span class="emphblue round-border border-frame" th:text="${sum.total}"></span></div> </div>
<div class="col-8"><span class="spanlabel">Pausezeit total:</span></div> <div class="col-8">
<div class="col-4"><span class="emphorange round-border border-frame" th:text="${sum.pause}"></span></div> <span class="spanlabel">Ende:</span>
<div class="col-8"><span class="spanlabel">Überstunden:</span></div> </div>
<div class="col-4"><span class="emphred round-border border-frame" th:text="${sum.overdue}"></span></div> <div class="col-4">
<span class="emphgreen round-border border-frame" th:text="${sum.end}"></span>
</div>
<div class="col-8">
<span class="spanlabel">Arbeitszeit total:</span>
</div>
<div class="col-4">
<span class="emphblue round-border border-frame" th:text="${sum.total}"></span>
</div>
<div class="col-8">
<span class="spanlabel">Pausezeit total:</span>
</div>
<div class="col-4">
<span class="emphorange round-border border-frame" th:text="${sum.pause}"></span>
</div>
<div class="col-8">
<span class="spanlabel">Überstunden:</span>
</div>
<div class="col-4">
<span class="emphred round-border border-frame" th:text="${sum.overdue}"></span>
</div> </div>
</div> </div>
</div> </div>
<div class="card-footer"> <div class="card-footer">
<span th:if="${sum.getBillingTime('WP2') != '0,0 h'}"><span class="billing WP2">WP2</span><span <span th:if="${sum.getBillingTime('WP2') != '0,0 h'}"><span class="billing WP2">WP2</span><span th:text="${sum.getBillingTime('WP2')}" class="distfat"></span></span> <span
th:text="${sum.getBillingTime('WP2')}" class="distfat"></span></span> <span th:if="${sum.getBillingTime('WP4') != '0,0 h'}"><span class="billing WP4">WP4</span><span th:text="${sum.getBillingTime('WP4')}" class="distfat"></span></span> <span
th:if="${sum.getBillingTime('WP4') != '0,0 h'}"><span class="billing WP4">WP4</span><span th:if="${sum.getBillingTime('WP5') != '0,0 h'}"><span class="billing WP5">WP5</span><span th:text="${sum.getBillingTime('WP5')}" class="distfat"></span></span> <span
th:text="${sum.getBillingTime('WP4')}" class="distfat"></span></span> <span th:if="${sum.getBillingTime('TA3') != '0,0 h'}"><span class="billing TA3">TA3</span><span th:text="${sum.getBillingTime('TA3')}" class="distfat"></span></span> <span class="billing">X</span><span
th:if="${sum.getBillingTime('WP5') != '0,0 h'}"><span class="billing WP5">WP5</span><span
th:text="${sum.getBillingTime('WP5')}" class="distfat"></span></span> <span
th:if="${sum.getBillingTime('TA3') != '0,0 h'}"><span class="billing TA3">TA3</span><span
th:text="${sum.getBillingTime('TA3')}" class="distfat"></span></span> <span class="billing">X</span><span
th:text="${sum.getBillingTime(null)}" class="distfat"></span> th:text="${sum.getBillingTime(null)}" class="distfat"></span>
</div> </div>
</div> </div>
</div>
</main> </main>
</body> </body>