Merge branch 'master' into 'fronkdev'

# Conflicts:
#   composer.json
This commit is contained in:
Frank Schubert
2024-02-14 12:58:02 +00:00
43 changed files with 13905 additions and 360 deletions

View File

@@ -0,0 +1,99 @@
<?php /** @noinspection PhpUndefinedClassInspection
* @var string $mfLayoutPackage
* @var TYPE_NAME $git_merge_ts
*/
//additional css /css/views/RaspberryDisplay.css
$JSGlobals = ["BASE_URL" => self::getUrl("RaspberryDisplay"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "Raspberry Displays",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "Raspberry Displays", "href" => self::getUrl("RaspberryDisplay")]
]
];
$additionalJS = ["plugins/vue/vue.min.js",
"plugins/axios/axios.min.js",
"plugins/vue/tt-components/tt-page-title.js",
"plugins/vue/tt-components/tt-loader.js"];
$additionalCSS = ["css/views/RaspberryDisplay.css", "plugins/vue/tt-components/css/tt-loader.css"];
include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<div id="app">
<!-- start page title -->
<tt-page-title :title="window['TT_CONFIG']['PAGE_TITLE']" :path="window['TT_CONFIG']['PATH']"></tt-page-title>
<div class="card">
<tt-loader v-if="loading"></tt-loader>
<div class="p-2">
<h3>8322 Studenzen NOC Displays</h3>
<div class="display-grid">
<div v-for="display in displays" :key="display.id"
:class="['display', display['display_label'].includes('-B-') ? 'big-42-inch' : 'small-27-inch']"
:style="display['custom_style']" style="">
<div style="display: grid; grid-template-columns: max-content auto max-content; justify-items: center;width:100%; padding: 0 2px">
<div>
<!-- FONT AWESOME ONLINE GREEN CIRCLE -->
<i class="fas fa-circle" data-toggle="tooltip" title="ONLINE" style="color: green"></i>
</div>
<div>
<div @click.prevent="enableDisplayURLEditMode(display.id)" style="cursor: pointer">
<span v-if="displaysURLEditMode !== display.id">{{ display['display_url'] | cleanupURL }}</span>
<input v-else-if="displaysURLEditMode === display.id"
v-model="display['display_url']"
@keyup.enter="disableDisplayURLEditMode(display.id, display['display_url'])"
@blur="disableDisplayURLEditMode(display.id, display['display_url'])"
ref="displayURLEditInput"
class="form-control"
type="text">
</div>
</div>
<div style="cursor: pointer">
<!-- FONT AWESOME REBOOT ICON -->
<i class="fas fa-red fa-sync-alt" data-toggle="tooltip" title="Reboot this Raspberry"
@click="rebootRaspberry(display.id)"
style="color: green"></i>
</div>
</div>
<div>
<!-- Checkbox for Auto Refresh Enabled -->
<div style="display: inline-block" data-toggle="tooltip"
:title="`Auto refresh is ${display['auto_refresh_enabled'] ? 'enabled' : 'disabled'}.`">
<input type="checkbox" :id="'auto_refresh_enabled_checkbox_' + display.id"
v-model="display['auto_refresh_enabled']"
@change="submitChanges(display.id, 'auto_refresh_enabled', display['auto_refresh_enabled'])">
<label :for="'auto_refresh_enabled_checkbox_' + display.id">ARF</label>
</div>
<!-- This will only display if both are true, consider adjusting logic as needed -->
<span style="margin: 0 4px"> | </span>
<!-- Checkbox for Margin Hotfix Enabled -->
<div style="display: inline-block" data-toggle="tooltip"
:title="`Margin Hotfix is ${display['margin_hot_fix_enabled'] ? 'enabled' : 'disabled'}.`">
<input type="checkbox" :id="'margin_hot_fix_enabled_checkbox_' + display.id"
v-model="display['margin_hot_fix_enabled']"
@change="submitChanges(display.id, 'margin_hot_fix_enabled', display['margin_hot_fix_enabled'])">
<label :for="'margin_hot_fix_enabled_checkbox_' + display.id">MHF</label>
</div>
</div>
<div v-text="display['display_label']"></div>
</div>
</div>
</div>
</div>
</div>
<script src="<?=self::getResourcePath()?>js/pages/raspberryDisplay.js?<?=$git_merge_ts?>"></script>

View File

@@ -19,10 +19,10 @@ for ($i = 1; $i <= 25; $i++) {
$year = date('Y', $time);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_freitag = strtotime("{$year}-W{$kw}-5");
$weeks[$time] = "KW" . $kw . " " . $year . " (" . date('d.m', $timestamp_montag) . "-" . date('d.m', $timestamp_freitag) . ")";
$time = $time - 604800;
}
$time = time();
for ($i = 1; $i <= 12; $i++) {
$mon = date('n', $time);
@@ -30,7 +30,12 @@ for ($i = 1; $i <= 12; $i++) {
$month[$time] = $monthger[$mon] . " " . $year;
$time = strtotime('-1 month', $time);
}
$years[time() + 31536000] = date('Y', time() + 31536000);
$years[time()] = date('Y', time());
$years[time() - 31536000] = date('Y', time() - 31536000);
?>
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
@@ -73,10 +78,19 @@ for ($i = 1; $i <= 12; $i++) {
font-weight: 500;
color: #000;
}
.text-normal {
color: #000;
}
.fixed-state {
background-color: #d0fbd9;
}
.form-check-label {
margin-top: 2px;
}
</style>
<!-- start page title -->
<div class="row">
@@ -111,7 +125,8 @@ for ($i = 1; $i <= 12; $i++) {
<option value="<?= $timerecordingCategories->id ?>"
data-approval="<?= $timerecordingCategories->approval ?>"
data-comment="<?= $timerecordingCategories->require_comment ?>"
data-hourday="<?= $timerecordingCategories->hourday ?>"><?= $timerecordingCategories->name ?></option>
data-hourday="<?= $timerecordingCategories->hourday ?>"
data-businesstrip="<?= $timerecordingCategories->businesstrip ?>"><?= $timerecordingCategories->name ?></option>
<?php
endif;
endforeach; ?>
@@ -158,25 +173,45 @@ for ($i = 1; $i <= 12; $i++) {
</div>
</div>
<div class="form-group col-lg-2">
<label class="col-form-label" for="commend">Anmerkung</label>
<input type="text" id="commend" name="commend" class="form-control"
<label class="col-form-label" for="comment">Anmerkung</label>
<input type="text" id="comment" name="comment" class="form-control"/>
</div>
</div>
<div class="row" id="businesstrip-div">
<div class="col-lg-2 mb-2">
<div class="form-check text-center mt-1">
<input class="form-check-input" type="checkbox" name="businesstrip" value=""
id="businesstrip">
<label class="form-check-label" for="businesstrip" value="1">
Dienstreise > 12KM
</label>
</div>
</div>
<div class="col-lg-2">
<input style="display:none" type="text" id="businesstrip_info" name="businesstrip_info"
placeholder="Ort"
class="form-control"/>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-2 ">
<button id="submit-button" type="submit" class="btn btn-primary">Speichern</button>
<button id="cancel-button" type="button" class="btn btn-secondary" style="display:none">
Abbrechen
</button>
</div>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-2 ">
<button id="submit-button" type="submit" class="btn btn-primary">Speichern</button>
<button id="cancel-button" type="button" class="btn btn-secondary" style="display:none">Abbrechen
</button>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-4" id="message-box">
</div>
</div>
</div>
</form>
@@ -188,9 +223,11 @@ for ($i = 1; $i <= 12; $i++) {
<label class="col-form-label label-calendar" for="lenght">Buchungszeitraum:</label>
</div>
<div class="col-6 col-lg-1 text-center">
<i class="fa-regular fa-calendar-week display-calendar active-calendar" title="Kalenderwoche"
data-datatype="1"></i> <i class="fa-regular fa-calendar-days display-calendar"
title="Kalendermonat" data-datatype="2"></i>
<i class="fa-duotone fa-calendar-week display-calendar active-calendar" title="Kalenderwoche"
data-datatype="1"></i> <i class="fa-duotone fa-calendar-days display-calendar"
title="Kalendermonat" data-datatype="2"></i> <i title="Abwesenheiten"
class="fa-duotone fa-calendar-clock display-calendar"
data-datatype="3"></i>
</div>
<div class="col-lg-2">
<div class="form-row">
@@ -212,9 +249,19 @@ for ($i = 1; $i <= 12; $i++) {
</select>
</div>
</div>
<div class="col" id="datayear-col" style="display:none">
<div class="input-group">
<select id="datayear" class="form-control select2">
<?php foreach ($years as $key => $Year): ?>
<option <?= (date('Y', time()) == $Year) ? "selected='selected'" : NULL ?>
value="<?= $key ?>"><?= $Year ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
</div>
<div class="col-lg-3">
<div id="dynamictime-div" class="col-lg-3">
<div class="form-row">
<div class="col text-center">
<div class="input-group ">
@@ -232,6 +279,25 @@ for ($i = 1; $i <= 12; $i++) {
</div>
</div>
</div>
<div class="col-lg-3">
<div class="form-row">
<div class="col text-center">
<div class="input-group ">
<label class="col-form-label form-control fixed-state"><span
class="text-bold">Urlaubstage: </span><span id="holidays"
class="ml-1 text-normal"></span></label>
</div>
</div>
<div class="col text-center">
<div class="input-group ">
<label class="col-form-label form-control fixed-state"><span
class="text-bold">Gutzeit: </span><span
id="plushours"
class="ml-1 text-normal"></span></label>
</div>
</div>
</div>
</div>
</div>
@@ -272,8 +338,6 @@ for ($i = 1; $i <= 12; $i++) {
let insertUrl = "<?= self::getUrl("Timerecording", "save") ?>";
let deleteUrl = "<?= self::getUrl("Timerecording", "delete") ?>";
let requestUrl = "<?= self::getUrl("Timerecording", "api", ['do' => 'getTimerecordings']) ?>";
</script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>js/pages/timerecording/index.js?<?= date('U') ?>"></script>

View File

@@ -80,6 +80,15 @@
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="businesstrip">Dienstreisemöglichkeit</label>
<div class="col-lg-3">
<div class="form-check">
<input id="businesstrip" class="form-check-input" <?php if ($timerecordingcategoriess->businesstrip) echo 'checked="checked"'; ?>
type="checkbox" name="businesstrip" value="1">
</div>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="only_admin">Nur für Buchhaltung zu buchen</label>
<div class="col-lg-3">

View File

@@ -40,6 +40,7 @@
<th class="text-center">BMD KZ</th>
<th class="text-center">Buchungszeitraum</th>
<th class="text-center">Genehmigungspflichtig</th>
<th class="text-center">Dienstreisemöglichkeit</th>
<th class="text-center">Anmerkung Pflichtfeld</th>
<th class="text-center">Nur Buchhaltung</th>
<th class="edit-width"></th>
@@ -52,17 +53,19 @@
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($timerecordingcategoriess as $timerecordingcategories): ?>
<tr>
<td><?= $timerecordingcategories->name ?></td>
<td><?= $timerecordingcategories->short ?></td>
<td><?= $timerecordingcategorieshourday[$timerecordingcategories->hourday] ?></td>
<td><?= $timerecordingcategoriesapproval[$timerecordingcategories->approval] ?></td>
<td><?= $timerecordingcategoriesrequire_comment[$timerecordingcategories->require_comment] ?></td>
<td><?= $timerecordingcategoriesrequire_comment[$timerecordingcategories->only_admin] ?></td>
<td class="text-center"><?= $timerecordingcategories->name ?></td>
<td class="text-center"><?= $timerecordingcategories->short ?></td>
<td class="text-center"><?= $timerecordingcategorieshourday[$timerecordingcategories->hourday] ?></td>
<td class="text-center"><?= $timerecordingcategoriesapproval[$timerecordingcategories->approval] ?></td>
<td class="text-center"><?= $timerecordingcategoriesbusinesstrip[$timerecordingcategories->businesstrip] ?></td>
<td class="text-center"><?= $timerecordingcategoriesrequire_comment[$timerecordingcategories->require_comment] ?></td>
<td class="text-center"><?= $timerecordingcategoriesrequire_only_admin[$timerecordingcategories->only_admin] ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("TimerecordingCategory", "edit", ["id" => $timerecordingcategories->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>
@@ -83,7 +86,7 @@
<script type="text/javascript">
var hidesearch = [6];
var hidesearch = [7];
$(document).ready(function () {

View File

@@ -70,6 +70,25 @@ $daysSelect .= "</select>";
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="type">Vertragsart *</label>
<div class="col-lg-3">
<select class="select2 form-control " name="type" id="type">
<option value="1" <?= ($timerecordingemployees->type == '1') ? "selected='selected'" : "" ?>>Angestellter</option>
<option value="2" <?= ($timerecordingemployees->type == '2') ? "selected='selected'" : "" ?>>Arbeiter</option>
<option value="3" <?= ($timerecordingemployees->type == '3') ? "selected='selected'" : "" ?>>Lehrling</option>
</select>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="startdate">Startdatum
Zeiterfassung</label>
<div class="col-lg-2">
<input required="required" type="date" id="startdate" name="startdate"
class="form-control"
value="<?= ($timerecordingemployees->startdate) ? date('Y-m-d', $timerecordingemployees->startdate): "" ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="holidays">Initiale Urlaubstage</label>
<div class="col-lg-1">
@@ -78,6 +97,7 @@ $daysSelect .= "</select>";
value="<?= $timerecordingemployees->holidays ?>"/>
</div>
</div>
<div class="form-group row">
<label class="col-lg-2 col-form-label" for="plushours">Initiale Gutstunden</label>
<div class="col-lg-1">

View File

@@ -1,4 +1,8 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php"); ?>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
$type[1] = "Angestellter";
$type[2] = "Arbeiter";
$type[3] = "Lehrling";
?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<!-- start page title -->
@@ -34,6 +38,8 @@
<thead>
<tr>
<th class="text-center">Mitarbeiter</th>
<th class="text-center">Vertragsart</th>
<th class="text-center">Start Zeitaufzeichnung</th>
<th class="text-center">Sollzeiten</th>
<th class="text-center">Sollstunden</th>
<th class="text-center edit-width">Schnellbuchung</th>
@@ -45,6 +51,8 @@
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
@@ -61,11 +69,13 @@
<tr>
<td><?= $timerecordinguser->name ?></td>
<td><?= $type[$timerecordingemployees[$timerecordinguser->id]['type']] ?></td>
<td class="text-center"><?= ($timerecordingemployees[$timerecordinguser->id]['startdate']) ? date("d.m.Y", $timerecordingemployees[$timerecordinguser->id]['startdate']) : "-" ?></td>
<td class="text-center"><?= ($timerecordingworkinghours) ? $timerecordingworkinghours[$timerecordinguser->id]['datetimetext'] : "" ?></td>
<td class="text-center"><?= $sum ?></td>
<td class="text-center"><?= ($timerecordingemployees[$timerecordinguser->id]['auto_workinghours'] == '1') ? 'Ja' : 'Nein' ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("TimerecordingEmployee", "edit", ['id'=> $timerecordingemployees[$timerecordinguser->id]['id'],"userid" => $timerecordinguser->id]) ?>"><i
<a href="<?= self::getUrl("TimerecordingEmployee", "edit", ['id' => $timerecordingemployees[$timerecordinguser->id]['id'], "userid" => $timerecordinguser->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>
</td>
</tr>
@@ -81,7 +91,7 @@
<script type="text/javascript">
var hidesearch = [4];
var hidesearch = [6];
$(document).ready(function () {

View File

@@ -3,7 +3,6 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
?>
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
<!-- start page title -->
@@ -33,7 +32,8 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
</div>
<div class="float-right">
<a class="btn btn-primary mb-2" href="<?= self::getUrl("TimerecordingHoliday", "add") ?>"><i
class="fas fa-plus"></i> Neuen Feiertag anlegen</a>
class="fas fa-plus"></i> <span
class="d-none d-lg-inline"> Neuen Feiertag anlegen</span></a>
</div>
</div>
</div>
@@ -41,8 +41,8 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
<thead>
<tr>
<th style="width: 200px;" class="text-center">Datum</th>
<th class="text-center">Name</th>
<th class="edit-width"></th>
<th class="text-center ">Name</th>
<th class="edit-width desktop"></th>
</tr>
<tr id="filterrow">
<th></th>
@@ -53,8 +53,8 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
<tbody>
<?php foreach ($timerecordingholidays as $timerecordingholiday): ?>
<tr>
<td data-order="<?= $timerecordingholiday->timestamp ?>"><?= $daysgerm[date("w", $timerecordingholiday->timestamp)]." ".date("d.m.Y", $timerecordingholiday->timestamp) ?></td>
<td><?= $timerecordingholiday->description ?></td>
<td data-order="<?= $timerecordingholiday->timestamp ?>"><?= $daysgerm[date("w", $timerecordingholiday->timestamp)] . " " . date("d.m.Y", $timerecordingholiday->timestamp) ?></td>
<td class="text-nowrap all"><?= $timerecordingholiday->description ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<a href="<?= self::getUrl("TimerecordingHoliday", "edit", ["id" => $timerecordingholiday->id]) ?>"><i
class="far fa-edit" title="Bearbeiten"></i></a>

View File

@@ -121,7 +121,7 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
$enddate = date("Y-m-d", $timerecording->end);
$start = "-";
$end = "-";
$day=$daysgerm[date("w", $timerecording->start)];
$day = $daysgerm[date("w", $timerecording->start)];
} else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
@@ -141,13 +141,14 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
// if ($timerecording->completed == 1) $completed = 'Genehmigt';
?>
<tr class="">
<td data-order="<?= $orderdate ?>" class="text-nowrap "><?= $state ?><?= $day . " " . $date ?></td>
<td data-order="<?= $orderdate ?>"
class="text-nowrap "><?= $state ?><?= $day . " " . $date ?></td>
<td class="text-nowrap "><?= $timerecording->user->name ?></td>
<td class="text-nowrap text-center"><?= $start ?></td>
<td class="text-nowrap text-center"><?= $end ?></td>
<td class="text-nowrap text-center"><?= $sum ?></td>
<td class="text-nowrap"><?= $timerecording->timerecordingCategory->name ?></td>
<td><?= $timerecording->commend ?></td>
<td><?= $timerecording->comment ?></td>
<td class="text-center"><?= $approved ?></td>
<td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">
<?php if ($timerecording->completed == 0):
@@ -156,30 +157,14 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
onclick="if(!confirm('Buchung genehmigen?')) return false;"> <i
class="fa-regular fa-square-check permit-button" title="genehmigen"
data-id="<?= $timerecording->id ?>"></i></a>
<a href="<?php self::getUrl("TimerecordingPermit", "deny", ["id" => $timerecording->id]) ?>"
onclick="if(!confirm('Buchung wirklich ablehnen?')) return false;"
class="text-danger"
title="Ablehnen"><i class="fas fa-ban deny-button"></i></a>
<a href="<?= self::getUrl("TimerecordingPermit", "deny", ["id" => $timerecording->id]) ?>"
onclick="if(!confirm('Buchung wirklich ablehnen?')) return false;"> <i
class="fas fa-ban deny-button" title="genehmigen"
data-id="<?= $timerecording->id ?>"></i></a>
<?php else : ?>
<div class="edit-placeholder"></div>
<?php endif; ?>
<!-- <i class="far fa-edit edit-button" data-id="--><?php //= $timerecording->id
?><!--"-->
<!-- data-date="--><?php //= $datadate
?><!--"-->
<!-- data-category="--><?php //= $timerecording->timerecordingCategory->id
?><!--"-->
<!-- data-start="--><?php //= $start
?><!--"-->
<!-- data-end="--><?php //= $end
?><!--"-->
<!-- data-enddate="--><?php //= $enddate
?><!--"-->
<!-- title="Bearbeiten"></i>-->
<!-- <a href="--><?php //= self::getUrl("Timerecording", "delete", ["id" => $timerecording->id])
?><!--"-->
<!-- onclick="if(!confirm('Buchung wirklich löschen?')) return false;" class="text-danger"-->
<!-- title="Löschen"><i class="fas fa-trash"></i></a>-->
<?php endif; ?>
</td>
</tr>
@@ -199,89 +184,9 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
var columnfilter = [7];
var columnoptions = '<option value=""></option><option value="Offen">Offen</option><option value="Genehmigt">Genehmigt</option><option value="Abgelehnt">Abgelehnt</option>';
$(document).ready(function () {
$(".select2").select2();
$("body").on("change", "#timerecordingCategory_id", function () {
if (parseInt($(this).find(':selected').data('hourday')) === 2) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
});
$("#enddate-div").show();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", true);
$(this).prop("min", $('#date').val());
$(this).val($('#date').val());
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 1) {
$("#endtime-div").show();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", true);
$(this).prop("disabled", false);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 3 || parseInt($(this).find(':selected').data('hourday')) === 4) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("disabled", true);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
}
if (parseInt($(this).find(':selected').data('comment')) === 1) {
$('#commend').prop("required", true);
} else {
$('#commend').prop("required", false);
}
});
$("body").on("change", "#date", function () {
if ($('#enddate-div').css('display') === "block") {
if ($('#date').val() > $('#enddate').val()) {
$('#enddate').prop("min", $('#date').val());
$('#enddate').val($('#date').val());
}
}
});
$("body").on("change", "#date", function () {
if ($('#endtime').css('display') === "block") {
if ($('#start').val() > $('#end').val()) {
console.log('größer');
$('#end').prop("min", $('#start').val());
$('#end').val($('#start').val());
}
}
});
$("body").on("click", ".edit-button", function () {
$('#submit-button').hide().removeClass('btn-primary').addClass('btn-danger').show();
$('#submit-button').text('Ändern');
$('#cancel-button').show();
$('#timerecordingCategory_id').val($(this).data('category')).change();
$('#id').val($(this).data('id'));
$('#date').val($(this).data('date'));
$('#start').val($(this).data('start'));
$('#end').val($(this).data('end'));
$('#enddate').val($(this).data('enddate'));
window.scrollTo(0, 0);
});
$("body").on("click", "#cancel-button", function () {
$('#submit-button').hide().removeClass('btn-danger').addClass('btn-primary').show();
$('#submit-button').text('Speichern');
$('#cancel-button').hide();
$('#id').val('');
});
});
</script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/datatables-std.js?<?= date('U') ?>"></script>

View File

@@ -1,5 +1,46 @@
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
$daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
$monthger[1] = "Jänner";
$monthger[2] = "Februar";
$monthger[3] = "März";
$monthger[4] = "April";
$monthger[5] = "Mai";
$monthger[6] = "Juni";
$monthger[7] = "Juli";
$monthger[8] = "August";
$monthger[9] = "September";
$monthger[10] = "Oktober";
$monthger[11] = "November";
$monthger[12] = "Dezember";
$time = time();
foreach ($timerecordingusers as $timerecordinguser) {
$timerecordingUsers[$timerecordinguser->name] = $timerecordinguser->id;
}
ksort($timerecordingUsers);
for ($i = 1; $i <= 25; $i++) {
$kw = date('W', $time);
$year = date('Y', $time);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_freitag = strtotime("{$year}-W{$kw}-5");
$weeks[$time] = "KW" . $kw . " " . $year . " (" . date('d.m', $timestamp_montag) . "-" . date('d.m', $timestamp_freitag) . ")";
$time = $time - 604800;
}
$time = time();
for ($i = 1; $i <= 12; $i++) {
$mon = date('n', $time);
$year = date('Y', $time);
$month[$time] = $monthger[$mon] . " " . $year;
$time = strtotime('-1 month', $time);
}
$years[time() + 31536000] = date('Y', time() + 31536000);
$years[time()] = date('Y', time());
$years[time() - 31536000] = date('Y', time() - 31536000);
?>
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.css?<?= date('U') ?>" rel="stylesheet"
type="text/css"/>
@@ -31,10 +72,26 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
.edit-placeholder {
height: 15px;
width: 19px;
width: 27px;
display: inline-block;
}
.fa-trash {
cursor: pointer;
}
.text-bold {
font-weight: 500;
color: #000;
}
.text-normal {
color: #000;
}
.fixed-state {
background-color: #d0fbd9;
}
</style>
<!-- start page title -->
@@ -52,29 +109,201 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
</div>
</div>
</div>
<!-- end page title -->
<div class="card">
<div class="card-body mb-3">
<div class="row">
<div class="col-12">
<div class="float-left">
<h4 class="header-title">Liste aller Buchungen</h4>
<form class="form-horizontal" method="post"
action="<?= self::getUrl("Timerecording", "save") ?>">
<div class="card">
<div class="card-body">
<input id="id" type="hidden" name="id" value=""/>
<div class="form-row">
<div class="form-group col-lg-2">
<label class="col-form-label" for="user_id">Buchungsart</label>
<select id="user_id_select" name="user_id"
class="select2 form-control" required="required">
<?php foreach ($timerecordingUsers as $key => $timerecordingUser): ?>
<option value="<?= $timerecordingUser ?>"><?= $key ?></option>
<?php
endforeach; ?>
</select>
<input id="user_id_input" name="user_id" disabled="disabled" style="display:none">
</div>
<div class="form-group col-lg-2">
<label class="col-form-label" for="timerecordingCategory_id">Buchungsart</label>
<select id="timerecordingCategory_id" name="timerecordingCategory_id"
class="select2 form-control" required="required">
<?php foreach ($timerecordingCategoriess as $timerecordingCategories): ?>
<option value="<?= $timerecordingCategories->id ?>"
data-approval="<?= $timerecordingCategories->approval ?>"
data-comment="<?= $timerecordingCategories->require_comment ?>"
data-hourday="<?= $timerecordingCategories->hourday ?>"><?= $timerecordingCategories->name ?></option>
<?php
endforeach; ?>
</select>
</div>
<div class="form-group col-lg-1">
<label class="col-form-label" for="date">Datum</label>
<div class="form-row">
<div class="col">
<input type="date" id="date" name="date" class="form-control "
value="<?= date("Y-m-d", time()) ?>"
placeholder="<?= date("d.m.Y", time()); ?>" required="required"/>
</div>
</div>
</div>
<div id="enddate-div" class="form-group col-lg-1" style="display:none">
<label class="col-form-label" for="enddate">bis Datum</label>
<div class="form-row">
<div class="col">
<input type="date" id="enddate" name="enddate" class="form-control "
value=""
placeholder=""/>
</div>
</div>
</div>
<div id="endtime-div" class="col-lg-2">
<div class="form-row">
<div class="form-group col">
<label class=" col-form-label" for="start">Von</label>
<input type="time" id="start" name="start" class="form-control "
value="08:00" placeholder="07:00" required="required"/>
</div>
<div class="form-group col">
<label class=" col-form-label" for="end">Bis</label>
<input type="time" id="end" name="end" class="form-control "
value="15:00" min="08:00" placeholder="15:00" required="required"/>
</div>
</div>
</div>
<div class="form-group col-lg-2">
<label class="col-form-label" for="comment">Anmerkung</label>
<input type="text" id="comment" name="comment" class="form-control"
</div>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-2 ">
<button id="submit-button" type="submit" class="btn btn-primary">Speichern</button>
<button id="cancel-button" type="button" class="btn btn-secondary" style="display:none">Abbrechen
</button>
</div>
</div>
<div class=" row mt-2">
<div class="col-lg-4" id="message-box">
</div>
</div>
</div>
</form>
</div>
<div class="card">
<div class="card-body mb-3">
<div class="form-group module-row row mb-3">
<div class="col-6 col-lg-1">
<label class="col-form-label label-calendar" for="lenght">Buchungszeitraum:</label>
</div>
<div class="col-6 col-lg-1 text-center">
<i class="fa-duotone fa-calendar-week display-calendar active-calendar" title="Kalenderwoche"
data-datatype="1"></i> <i class="fa-duotone fa-calendar-days display-calendar"
title="Kalendermonat" data-datatype="2"></i> <i title="Abwesenheiten"
class="fa-duotone fa-calendar-clock display-calendar"
data-datatype="3"></i>
</div>
<div class="col-lg-2">
<div class="form-row">
<div class="col" id="dataweek-col">
<div class="input-group">
<select id="dataweek" class="form-control select2">
<?php foreach ($weeks as $key => $week): ?>
<option value="<?= $key ?>"><?= $week ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col" id="datamonth-col" style="display:none">
<div class="input-group">
<select id="datamonth" class="form-control select2">
<?php foreach ($month as $key => $Month): ?>
<option value="<?= $key ?>"><?= $Month ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="col" id="datayear-col" style="display:none">
<div class="input-group">
<select id="datayear" class="form-control select2">
<?php foreach ($years as $key => $Year): ?>
<option <?= (date('Y', time()) == $Year) ? "selected='selsected'" : NULL ?>
value="<?= $key ?>"><?= $Year ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
</div>
<div id="dynamictime-div" class="col-lg-3">
<div class="form-row">
<div class="col text-center">
<div class="input-group ">
<label class="col-form-label form-control"><span
class="text-bold">Sollzeit: </span><span id="must-time"
class="ml-1 text-normal"></span></label>
</div>
</div>
<div class="col text-center">
<div class="input-group ">
<label class="col-form-label form-control"><span class="text-bold">Istzeit: </span><span
id="is-time"
class="ml-1 text-normal"></span></label>
</div>
</div>
</div>
</div>
<!-- <div class="col-lg-3">-->
<!-- <div class="form-row">-->
<!-- <div class="col text-center">-->
<!-- <div class="input-group ">-->
<!-- <label class="col-form-label form-control fixed-state"><span-->
<!-- class="text-bold">Urlaubstage: </span><span id="holidays"-->
<!-- class="ml-1 text-normal"></span></label>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col text-center">-->
<!-- <div class="input-group ">-->
<!-- <label class="col-form-label form-control fixed-state"><span-->
<!-- class="text-bold">Gutzeit: </span><span-->
<!-- id="plushours"-->
<!-- class="ml-1 text-normal"></span></label>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
<table id="datatable" class="table table-hover table-sm">
<thead>
<tr>
<th class="text-center text-nowrap ">Mitarbeiter</th>
<th style="width: 200px;" class="text-center text-nowrap ">Datum</th>
<th style="width: 200px;" class="text-nowrap">Mitarbeiter</th>
<th class="text-nowrap text-center edit-width">Von</th>
<th class="text-nowrap text-center edit-width">Bis</th>
<th class="text-nowrap edit-width text-center">Von</th>
<th class="text-nowrap edit-width text-center">Bis</th>
<th class="text-nowrap edit-width text-center">Summe</th>
<th class="text-center text-nowrap">Buchungsart</th>
<th class="text-center">Anmerkung</th>
<th class="text-center edit-width">Verbucht</th>
<!-- <th class="edit-width"></th>-->
<th class="edit-width"></th>
</tr>
<tr id="filterrow">
<th></th>
@@ -85,79 +314,9 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
<th></th>
<th></th>
<th></th>
<!-- <th></th>-->
</tr>
</thead>
<tbody>
<?php foreach ($timerecordings as $timerecording):
$state = "";
$enddate = "";
$sum = "-";
$day = "";
$orderdate = $timerecording->start;
if ($timerecording->timerecordingCategory->hourday == 1) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = date("H:i", $timerecording->start);
$end = date("H:i", $timerecording->end);
$seconds = $timerecording->end - $timerecording->start;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
} else if ($timerecording->timerecordingCategory->hourday == 2) {
$date = date("d.m.", $timerecording->start) . " - " . $daysgerm[date("w", $timerecording->end)] . " " . date("d.m.Y", $timerecording->end);
$datadate = date("Y-m-d", $timerecording->start);
$enddate = date("Y-m-d", $timerecording->end);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
} else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
}
if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 0) {
$state = '<i class="fa-regular fa-clock mr-1"></i>';
} else if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 1) {
$state = '<i class="fa-regular fa-circle-check mr-1"></i>';
}
$completed = 'Nein';
if ($timerecording->completed == 1) $completed = 'Ja';
?>
<tr class="">
<td data-order="<?= $orderdate ?>" class="text-nowrap "><?= $state ?><?= $day . " " . $date ?></td>
<td class="text-nowrap "><?= $timerecording->user->name ?></td>
<td class="text-nowrap text-center"><?= $start ?></td>
<td class="text-nowrap text-center"><?= $end ?></td>
<td class="text-nowrap text-center"><?= $sum ?></td>
<td class="text-nowrap"><?= $timerecording->timerecordingCategory->name ?></td>
<td><?= $timerecording->commend ?></td>
<td><?= $completed ?></td>
<!-- <td style="text-align: left; letter-spacing: 4px; font-size: 1.1em;">-->
<!-- --><?php //if ($timerecording->completed == 0):
// if ($timerecording->approved == 0) : ?>
<!-- <i class="far fa-edit edit-button" data-id="--><?php //= $timerecording->id ?><!--"-->
<!-- data-date="--><?php //= $datadate ?><!--"-->
<!-- data-category="--><?php //= $timerecording->timerecordingCategory->id ?><!--"-->
<!-- data-start="--><?php //= $start ?><!--"-->
<!-- data-end="--><?php //= $end ?><!--"-->
<!-- data-enddate="--><?php //= $enddate ?><!--"-->
<!-- title="Bearbeiten"></i>-->
<!-- --><?php //else : ?>
<!-- <div class="edit-placeholder"></div>-->
<!-- --><?php //endif; ?>
<!-- <a href="--><?php //= self::getUrl("Timerecording", "delete", ["id" => $timerecording->id]) ?><!--"-->
<!-- onclick="if(!confirm('Buchung wirklich löschen?')) return false;" class="text-danger"-->
<!-- title="Löschen"><i class="fas fa-trash"></i></a>-->
<!-- --><?php //endif; ?>
<!-- </td>-->
</tr>
<?php endforeach; ?>
</tbody>
</table>
@@ -169,96 +328,15 @@ $daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
<script type="text/javascript">
var hidesearch = [2, 3, 4, 8];
var columnfilter = [7];
var columnoptions = '<option value=""></option><option value="Ja">Ja</option><option value="Nein">Nein</option>';
$(document).ready(function () {
$(".select2").select2();
var hidesearch = [2, 3, 4, 7];
let insertUrl = "<?= self::getUrl("Timerecording", "save") ?>";
let deleteUrl = "<?= self::getUrl("Timerecording", "delete") ?>";
let requestUrl = "<?= self::getUrl("TimerecordingReport", "api", ['do' => 'getTimerecordings']) ?>";
$("body").on("change", "#timerecordingCategory_id", function () {
if (parseInt($(this).find(':selected').data('hourday')) === 2) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
});
$("#enddate-div").show();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", true);
$(this).prop("min", $('#date').val());
$(this).val($('#date').val());
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 1) {
$("#endtime-div").show();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", true);
$(this).prop("disabled", false);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 3 || parseInt($(this).find(':selected').data('hourday')) === 4) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("disabled", true);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
}
if (parseInt($(this).find(':selected').data('comment')) === 1) {
$('#commend').prop("required", true);
} else {
$('#commend').prop("required", false);
}
});
$("body").on("change", "#date", function () {
if ($('#enddate-div').css('display') === "block") {
if ($('#date').val() > $('#enddate').val()) {
$('#enddate').prop("min", $('#date').val());
$('#enddate').val($('#date').val());
}
}
});
$("body").on("change", "#date", function () {
if ($('#endtime').css('display') === "block") {
if ($('#start').val() > $('#end').val()) {
console.log('größer');
$('#end').prop("min", $('#start').val());
$('#end').val($('#start').val());
}
}
});
$("body").on("click", ".edit-button", function () {
$('#submit-button').hide().removeClass('btn-primary').addClass('btn-danger').show();
$('#submit-button').text('Ändern');
$('#cancel-button').show();
$('#timerecordingCategory_id').val($(this).data('category')).change();
$('#id').val($(this).data('id'));
$('#date').val($(this).data('date'));
$('#start').val($(this).data('start'));
$('#end').val($(this).data('end'));
$('#enddate').val($(this).data('enddate'));
window.scrollTo(0, 0);
});
$("body").on("click", "#cancel-button", function () {
$('#submit-button').hide().removeClass('btn-danger').addClass('btn-primary').show();
$('#submit-button').text('Speichern');
$('#cancel-button').hide();
$('#id').val('');
});
});
</script>
<script type="text/javascript"
src="<?= self::getResourcePath() ?>assets/js/datatables-std.js?<?= date('U') ?>"></script>
src="<?= self::getResourcePath() ?>js/pages/timerecordingReport/index.js?<?= $git_merge_ts ?>"></script>
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>

View File

@@ -23,7 +23,7 @@
<?php if(isset($additionalCSS) && is_array($additionalCSS) && count($additionalCSS)): ?>
<?php foreach($additionalCSS as $css): ?>
<link rel="stylesheet" href="<?=self::getResourcePath()?><?=$css?>" />
<link rel="stylesheet" href="<?=self::getResourcePath()?><?=$css?>?<?=$git_merge_ts?>" />
<?php endforeach; ?>
<?php endif; ?>
@@ -39,10 +39,19 @@
<script type="text/javascript" src="<?=self::getResourcePath()?>assets/js/bootstrap-select.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>js/bootstrap-autocomplete.min.js"></script>
<script type="text/javascript" src="<?=self::getResourcePath()?>datatables/datatables.min.js?<?=$git_merge_ts?>"></script>
<?php if(isset($JSGlobals) && is_array($JSGlobals) && count($JSGlobals)): ?>
<script type="text/javascript">
window.TT_CONFIG = {};
<?php foreach($JSGlobals as $key => $value): ?>
window.TT_CONFIG.<?=$key?> = <?=is_array($value) ? json_encode($value) : "'$value'"; ?>;
<?php endforeach; ?>
</script>
<?php endif; ?>
<?php if(isset($additionalJS) && is_array($additionalJS) && count($additionalJS)): ?>
<?php foreach($additionalJS as $js): ?>
<script src="<?=self::getResourcePath()?><?=$js?>"></script>
<script src="<?=self::getResourcePath()?><?=$js?>?<?=$git_merge_ts?>"></script>
<?php endforeach; ?>
<?php endif; ?>

View File

@@ -26,6 +26,9 @@
<a href="<?=self::getUrl("Dashboard")?>"><i class="fe-airplay"></i> Dashboard <div class="arrow-down"></div></a>
<ul class="submenu">
<li><a href="<?=self::getUrl("News")?>"><i class="far fa-fw fa-th-list text-info"></i> News</a></li>
<?php if($me->is("employee")): ?>
<li><a href="<?=self::getUrl("RaspberryDisplay")?>"><i class="far fa-fw fa-tv text-info"></i> Raspberry Display</a></li>
<?php endif; ?>
</ul>
</li>
<?php endif; ?>

View File

@@ -0,0 +1,6 @@
<?php
class RaspberryDisplay extends mfBaseModel
{
}

View File

@@ -0,0 +1,130 @@
<?php
use phpseclib3\Net\SSH2;
class RaspberryDisplayController extends mfBaseController
{
private int $port = 22;
private string $username = XINON_RASPBERRY_DISPLAY_SSH_USER;
private string $password = XINON_RASPBERRY_DISPLAY_SSH_PASS;
protected function init(): void
{
$me = new User();
$me->loadMe();
$this->me = $me;
$this->layout()->set("me", $me);
}
protected function restartRaspberryPi($id) {
$display = RaspberryDisplayModel::get($id);
$ssh = new SSH2($display->ip_address, $this->port);
$ssh->login($this->username, $this->password);
$ssh->exec('sudo reboot now');
return true;
}
protected function getDisplaysApi(): array
{
$displays = RaspberryDisplayModel::getAll();
$result = [];
foreach ($displays as $display) {
$result[] = [
"display_label" => $display->display_label,
"hostname" => $display->hostname,
"ip" => $display->ip_address,
"display_url" => $display->display_url,
"auto_refresh_enabled" => $display->auto_refresh_enabled === "1",
"margin_hot_fix_enabled" => $display->margin_hot_fix_enabled === "1",
"custom_style" => $display->custom_style,
"id" => $display->id,
];
}
return $result;
}
protected function change()
{
$displayID = $this->request->displayID;
$field = $this->request->field;
$value = $this->request->value;
$value = $value === "true" ? 1 : ($value === "false" ? 0 : $value);
$display = RaspberryDisplayModel::get($displayID);
if ($display === null) {
return false;
}
$display->$field = $value;
$display->save();
return true;
}
protected function getConfig() {
$ip = $_SERVER['REMOTE_ADDR'];
$hostname = $this->request->hostname;
$displays = RaspberryDisplayModel::getByHostnameAndIp($hostname, $ip);
if ($displays === null) {
die("No display found for this hostname and ip:" . $hostname . " X " . $ip);
}
return array_map(function ($display) {
return [
"display_url" => $display->data->display_url,
"auto_refresh_enabled" => $display->data->auto_refresh_enabled === "1",
"margin_hot_fix_enabled" => $display->data->margin_hot_fix_enabled === "1",
"id" => $display->id,
];
}
, $displays);
}
protected function apiAction() {
$do = $this->request->do;
if (!$this->me->is("employee") && !in_array($do, ["getDisplays", "change", "reboot"])) {
$this->redirect("dashboard");
}
switch ($do) {
case "getDisplays":
$return = $this->getDisplaysApi();
break;
case "change":
$return = $this->change();
break;
case "reboot":
$return = $this->restartRaspberryPi($this->request->displayID);
break;
case "getConfig":
$return = $this->getConfig();
break;
default:
$return = false;
break;
}
$data = [];
if ($return === true) {
$data = ["status" => "success"];
$this->returnJson($data);
}
if(!is_array($return) || !count($return)) {
$data = ["status" => "error"];
$this->returnJson($data);
}
$data['status'] = "OK";
$data['result'] = $return;
$this->returnJson($data);
}
protected function indexAction(): void
{
$this->layout()->setTemplate("RaspberryDisplay/Index");
}
}

View File

@@ -0,0 +1,103 @@
<?php
class RaspberryDisplayModel
{
public $display_label;
public $hostname;
public $ip_address;
public $display_url;
public $auto_refresh_enabled;
public $margin_hot_fix_enabled;
public function __construct($data = [])
{
foreach ($data as $field => $value) {
if (property_exists(get_called_class(), $field)) {
$this->$field = $value;
}
}
}
public static function get($id)
{
$db = FronkDB::singleton();
$res = $db->select("RaspberryDisplay", "*", "id = $id");
if ($db->num_rows($res)) {
return new RaspberryDisplay($db->fetch_object($res));
}
return null;
}
public static function getByHostnameAndIp($hostname, $ip)
{
$db = FronkDB::singleton();
$res = $db->select("RaspberryDisplay", "*", "hostname = '$hostname' AND ip_address = '$ip'");
//fetch 2 rows
if ($db->num_rows($res)) {
while ($data = $db->fetch_object($res)) {
$items[] = new RaspberryDisplay($data);
}
return $items;
}
}
public static function create(array $data)
{
$model = new RaspberryDisplay();
foreach ($data as $field => $value) {
if (property_exists(get_called_class(), $field)) {
$model->$field = $value;
}
}
$me = new User();
$me->loadMe();
if ($model->create_by === null) {
$model->create_by = $me->id;
}
if ($model->edit_by === null) {
$model->edit_by = $me->id;
}
return $model;
}
public static function getAll()
{
$items = [];
$db = FronkDB::singleton();
$res = $db->select("RaspberryDisplay", "id, display_label, hostname, ip_address,custom_style, display_url, auto_refresh_enabled, margin_hot_fix_enabled");
if ($db->num_rows($res)) {
while ($data = $db->fetch_object($res)) {
$items[] = new RaspberryDisplay($data);
}
}
return $items;
}
public static function save(RaspberryDisplay $model)
{
$db = FronkDB::singleton();
$data = $model->data;
if ($model->id) {
$db->update("RaspberryDisplay", $data, "id=" . $model->id);
} else {
$model->create = date("U");
$model->edit = date("U");
$model->id = $db->insert("RaspberryDisplay", $data);
}
return $model;
}
}

View File

@@ -29,12 +29,13 @@ class TimerecordingController extends mfBaseController
$datatype = $this->request->datatype;
$dataweek = $this->request->dataweek;
$datamonth = $this->request->datamonth;
$datayear = $this->request->datayear;
$data = [];
switch ($do) {
case "getTimerecordings":
$return = $this->getTimerecordingsApi($datatype, $dataweek, $datamonth);
$return = $this->getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear);
break;
default:
$return = false;
@@ -79,7 +80,14 @@ class TimerecordingController extends mfBaseController
protected function checkTimerecording($starttime, $endtime, $id = NULL)
{
$searchArray = ['user_id' => $this->me->id, 'starttime' => $starttime, 'endtime' => $endtime];
$r = $this->request;
if ($r->user_id) {
$userid = $r->user_id;
} else {
$userid = $this->me->id;
}
$searchArray = ['user_id' => $userid, 'starttime' => $starttime, 'endtime' => $endtime];
if ($id) {
$searchArray['id'] = $id;
}
@@ -87,6 +95,7 @@ class TimerecordingController extends mfBaseController
if ($timerecordings) {
$result['state'] = "error";
$result['error'] = "Zeitüberschneidung mit anderer Buchung";
} else {
$result['state'] = "success";
}
@@ -132,11 +141,15 @@ class TimerecordingController extends mfBaseController
}
$data = [];
$data['user_id'] = $this->me->id;
if ($r->user_id) {
$data['user_id'] = $r->user_id;
} else {
$data['user_id'] = $this->me->id;
}
$data['start'] = $starttime;
$data['end'] = $endtime;
$data['timerecordingCategory_id'] = trim($r->timerecordingCategory_id);
$data['commend'] = trim($r->commend);
$data['comment'] = trim($r->comment);
if (!$data['user_id']) {
$this->layout()->setFlash("Benutzer darf nicht leer sein", "error");
@@ -153,8 +166,8 @@ class TimerecordingController extends mfBaseController
if (!$data['timerecordingCategory_id']) {
$data['timerecordingCategory_id'] = NULL;
}
if (!$data['commend']) {
$data['commend'] = NULL;
if (!$data['comment']) {
$data['comment'] = NULL;
}
if ($mode == "edit") {
@@ -193,7 +206,7 @@ class TimerecordingController extends mfBaseController
$body .= 'von: ' . date("d.m.Y", $data['start']) . ' bis: ' . date("d.m.Y", $data['end']);
}
$email = new Emailnotification();
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' erstellt');
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' erstellt');
$email->setBody($body);
$email->setFrom('zeiterfassung@xinon.at', 'Xinon Zeiterfassung');
$email->setTo('daniel.spitzer@inode.at');
@@ -217,13 +230,22 @@ class TimerecordingController extends mfBaseController
}
protected function getTimerecordingsApi($datatype, $dataweek, $datamonth)
protected function getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear)
{
$mustSeconds = 0;
$isSeconds=0;
$isSeconds = 0;
$holiDays = 0;
$plusHours = 0;
$rows = [];
$employee = TimerecordingEmployeeModel::search(['user_id' => $this->me->id]);
if ($employee) {
$holiDays = $employee[0]->holidays;
$plusHours = $employee[0]->plushours;
}
$workinghours = TimerecordingEmployeeWorkingHourModel::search(['user_id' => $this->me->id]);
$holidays= TimerecordingHolidayModel::getAll();
$holidays = TimerecordingHolidayModel::getAll();
foreach ($workinghours as $workinghour) {
$whstart = strtotime(date('Y-m-d', time()) . " " . $workinghour->start . ":00");
@@ -243,8 +265,8 @@ class TimerecordingController extends mfBaseController
$year = date('Y', $dataweek);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_sonntag = strtotime("{$year}-W{$kw}-7");
$timestamp_sonntag = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $timestamp_montag, 'end' => $timestamp_sonntag];
$lastdate = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $timestamp_montag, 'end' => $lastdate];
$daycounter = '0';
@@ -261,7 +283,26 @@ class TimerecordingController extends mfBaseController
} else if ($datatype == 2) {
$firstdate = strtotime(date("Y-m-01", $datamonth));
$lastdate = strtotime(date("Y-m-t", $datamonth));
$daycount=date("t", $datamonth);
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 3) {
$firstdate = strtotime(date("Y-01-01", $datayear));
$lastdate = strtotime(date("Y-12-31 23:59:59", $datayear));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['user_id' => $this->me->id, 'start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
@@ -281,7 +322,8 @@ class TimerecordingController extends mfBaseController
$daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
$timerecordingCategoriess = TimerecordingCategoryModel::getAll();
$timerecordingcategories = TimerecordingCategoryModel::getAll();
$timerecordings = TimerecordingModel::search($searchArray);
$responsecount = count($timerecordings);
foreach ($timerecordings as $timerecording):
@@ -300,7 +342,7 @@ class TimerecordingController extends mfBaseController
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds=$isSeconds+$seconds;
$isSeconds = $isSeconds + $seconds;
} else if ($timerecording->timerecordingCategory->hourday == 2) {
$date = date("d.m.", $timerecording->start) . " - " . $daysgerm[date("w", $timerecording->end)] . " " . date("d.m.Y", $timerecording->end);
$datadate = date("Y-m-d", $timerecording->start);
@@ -308,7 +350,23 @@ class TimerecordingController extends mfBaseController
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
// echo $enddate-$datadate."<br>";
if ($lastdate < $timerecording->end) {
$endtimecalc = $lastdate;
} else {
$endtimecalc = $timerecording->end;
}
$summcounter = 0;
for ($i = $timerecording->start; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[date("w", $i)];
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
} else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
@@ -331,27 +389,31 @@ class TimerecordingController extends mfBaseController
data-start="' . $start . '"
data-end="' . $end . '"
data-enddate="' . $enddate . '"
data-commend="' . $timerecording->commend . '"
data-comment="' . $timerecording->comment . '"
title="Bearbeiten"></i>';
else :
$edit .= '<div class="edit-placeholder"></div>';
endif;
$edit .= '<i data-id="' . $timerecording->id . '" class="fas fa-trash text-danger delete-item" ></i>';
endif;
$rows[] = array(
'date' => array('date' => $state . $day . " " . $date, 'order' => $orderdate),
'start' => array('start' => $start, 'order' => $start),
'end' => array('end' => $end, 'order' => $end),
'sum' => array('sum' => $sum, 'order' => $sum),
'category' => array('category' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
'commend' => array('commend' => $timerecording->commend, 'order' => $timerecording->commend),
'edit' => array('edit' => $edit, 'order' => $edit),
);
if ($datatype == 3 && $timerecording->timerecordingCategory->hourday == 1) {
} else {
$rows[] = array(
'date' => array('date' => $state . $day . " " . $date, 'order' => $orderdate),
'start' => array('start' => $start, 'order' => $start),
'end' => array('end' => $end, 'order' => $end),
'sum' => array('sum' => $sum, 'order' => $sum),
'category' => array('category' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
'comment' => array('comment' => $timerecording->comment, 'order' => $timerecording->comment),
'edit' => array('edit' => $edit, 'order' => $edit),
);
}
endforeach;
$json['success'] = true;
$json['time']['is'] = sprintf('%02dh:%02dm',floor($isSeconds / 3600 ),floor($isSeconds / 60 % 60));
$json['time']['must'] = sprintf('%02dh:%02dm',floor($mustSeconds / 3600 ),floor($mustSeconds / 60 % 60));
$json['time']['is'] = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
$json['data'] = $rows;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;

View File

@@ -6,7 +6,7 @@ class TimerecordingModel
private $start;
private $end;
private $timerecordingCategory_id;
private $commend;
private $comment;
private $approved;
private $completed;

View File

@@ -22,9 +22,13 @@ class TimerecordingCategoryController extends mfBaseController
$this->layout()->setTemplate("TimerecordingCategories/Index");
$timerecordingcategoriesapproval = TimerecordingCategoryModel::$approval_definition;
$timerecordingcategorieshourday = TimerecordingCategoryModel::$hourday_definition;
$timerecordingcategoriesbusinesstrip = TimerecordingCategoryModel::$businesstrip_definition;
$timerecordingcategoriesrequire_comment = TimerecordingCategoryModel::$require_comment_definition;
$timerecordingcategoriesrequire_only_admin = TimerecordingCategoryModel::$require_only_admin;
$timerecordingcategoriess = TimerecordingCategoryModel::getAll();
$this->layout()->set("timerecordingcategoriesrequire_comment", $timerecordingcategoriesrequire_comment);
$this->layout()->set("timerecordingcategoriesrequire_only_admin", $timerecordingcategoriesrequire_only_admin);
$this->layout()->set("timerecordingcategoriesbusinesstrip", $timerecordingcategoriesbusinesstrip);
$this->layout()->set("timerecordingcategorieshourday", $timerecordingcategorieshourday);
$this->layout()->set("timerecordingcategoriesapproval", $timerecordingcategoriesapproval);
$this->layout()->set("timerecordingcategoriess", $timerecordingcategoriess);
@@ -82,6 +86,7 @@ class TimerecordingCategoryController extends mfBaseController
$data['approval'] = trim($r->approval);
$data['require_comment'] = trim($r->require_comment);
$data['only_admin'] = trim($r->only_admin);
$data['businesstrip'] = trim($r->businesstrip);
if (!$data['name']) {
@@ -99,7 +104,9 @@ class TimerecordingCategoryController extends mfBaseController
if (!$data['only_admin']) {
$data['only_admin'] = 0;
}
if (!$data['businesstrip']) {
$data['businesstrip'] = 0;
}
// var_dump($_FILES);
// var_dump($upload);
// exit;

View File

@@ -8,9 +8,12 @@ class TimerecordingCategoryModel
private $approval;
private $require_comment;
private $only_admin;
private $businesstrip;
public static $hourday_definition = array(1 => "Uhrzeit (von/bis)", 2 => "Tage (von/bis)", 3 => "Startdatum", 4 => "Enddatum");
public static $approval_definition = array(0 => "Nein", 1 => "Ja");
public static $require_comment_definition = array(0 => "Nein", 1 => "Ja");
public static $businesstrip_definition = array(0 => "Nein", 1 => "Ja");
public static $require_only_admin = array(0 => "Nein", 1 => "Ja");
public static function find($data)
{

View File

@@ -107,6 +107,8 @@ class TimerecordingEmployeeController extends mfBaseController
$data['auto_workinghours'] = trim($r->auto_workinghours);
$data['holidays'] = trim($r->holidays);
$data['plushours'] = $plushours;
$data['startdate'] = strtotime($r->startdate);
$data['type'] = trim($r->type);
if (!$data['user_id']) {
@@ -117,7 +119,6 @@ class TimerecordingEmployeeController extends mfBaseController
$data['auto_workinghours'] = 0;
}
if ($mode == "edit") {
$timerecordingemployees->update($data);

View File

@@ -3,9 +3,11 @@
class TimerecordingEmployeeModel
{
private $user_id;
private $type;
private $auto_workinghours;
private $holidays;
private $plushours;
private $startdate;
public static function find($data)
@@ -130,10 +132,10 @@ class TimerecordingEmployeeModel
$where = "1=1 ";
//var_dump($filter);exit;
if (array_key_exists("network_id", $filter)) {
$networkid = $filter['network_id'];
if (is_numeric($networkid)) {
$where .= " AND network_id=$networkid";
if (array_key_exists("user_id", $filter)) {
$userid = $filter['user_id'];
if (is_numeric($userid)) {
$where .= " AND user_id=$userid";
}
}

View File

@@ -42,6 +42,37 @@ class TimerecordingPermitController extends mfBaseController
{
}
protected function sendMail($timerecordings, $type)
{
if ($type == "deny") {
$sendtext = "abgelehnt";
} else if ($type == "approve") {
$sendtext = "genehmigt";
}
$user = UserModel::getOne($timerecordings->user_id);
$timerecordingCategoriess = TimerecordingCategoryModel::search(['id' => $timerecordings->timerecordingCategory_id]);
$body = 'Beantrag von: ' . $user->name . '
';
$body .= 'Buchungsart: ' . $timerecordingCategoriess[0]->name . '
';
if ($timerecordingCategoriess[0]->hourday == "1") {
$body .= 'von: ' . date("d.m.Y H:i", $timerecordings->start) . ' bis: ' . date("H:i", $timerecordings->end). '
';
} else if ($timerecordingCategoriess[0]->hourday == "2") {
$body .= 'von: ' . date("d.m.Y", $timerecordings->start) . ' bis: ' . date("d.m.Y", $timerecordings->end) . '
';
}
$body .= ucfirst($sendtext) . ' von: ' . $this->me->name . '
';
$email = new Emailnotification();
$email->setSubject('Antrag für ' . $timerecordingCategoriess[0]->name . ' ' . $sendtext);
$email->setBody($body);
$email->setFrom('zeiterfassung@xinon.at', 'Xinon Zeiterfassung');
$email->setTo($user->email);
$email->send();
}
protected function approveAction()
{
@@ -55,7 +86,25 @@ class TimerecordingPermitController extends mfBaseController
$data['approved'] = 1;
$timerecordings->update($data);
$timerecordings->save();
$this->sendMail($timerecordings, "approve");
$this->redirect("TimerecordingPermit");
}
protected function denyAction()
{
$id = $this->request->id;
$timerecordings = new Timerecording($id);
if (!$timerecordings->id || $timerecordings->id != $id) {
$this->layout()->setFlash("Buchung nicht gefunden.", "error");
$this->redirect("TimerecordingPermit");
}
$this->sendMail($timerecordings, "deny");
$timerecordings->delete();
if ($this->request->ajax == 1) {
die();
}
$this->redirect("TimerecordingPermit");
}

View File

@@ -18,13 +18,231 @@ class TimerecordingReportController extends mfBaseController
protected function indexAction()
{
$this->layout()->setTemplate("TimerecordingReport/Index");
$timerecordingCategoriess = TimerecordingCategoryModel::getAll();
$this->layout()->set("timerecordingCategoriess", $timerecordingCategoriess);
$timerecordingusers = UserModel::search(['employee' => 'true']);
$this->layout()->set("timerecordingusers", $timerecordingusers);
$timerecordings = TimerecordingModel::getAll();
$this->layout()->set("timerecordings", $timerecordings);
}
protected function apiAction()
{
$do = $this->request->do;
$datatype = $this->request->datatype;
$dataweek = $this->request->dataweek;
$datamonth = $this->request->datamonth;
$datayear = $this->request->datayear;
$data = [];
switch ($do) {
case "getTimerecordings":
$return = $this->getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear);
break;
default:
$return = false;
}
if (!is_array($return) || !count($return)) {
$data = ["status" => "error"];
$this->returnJson($data);
}
$data['status'] = "OK";
$data['result'] = $return;
$this->returnJson($data);
}
protected function getTimerecordingsApi($datatype, $dataweek, $datamonth, $datayear)
{
$mustSeconds = 0;
$isSeconds = 0;
$holiDays = 0;
$plusHours = 0;
$rows = [];
$employee = TimerecordingEmployeeModel::getAll();
if ($employee) {
$holiDays = $employee[0]->holidays;
$plusHours = $employee[0]->plushours;
}
$workinghours = TimerecordingEmployeeWorkingHourModel::getAll();
$holidays = TimerecordingHolidayModel::getAll();
foreach ($workinghours as $workinghour) {
$whstart = strtotime(date('Y-m-d', time()) . " " . $workinghour->start . ":00");
$whend = strtotime(date('Y-m-d', time()) . " " . $workinghour->end . ":00");
if (!$workingHours[$workinghour->day]) {
$workingHours[$workinghour->day] = $whend - $whstart;
} else {
$workingHours[$workinghour->day] = $workingHours[$workinghour->day] + $whend - $whstart;
}
}
foreach ($holidays as $holiday) {
$holiDay[date('Y-m-d', $holiday->timestamp)] = $holiday->timestamp;
}
if ($datatype == 1) {
$kw = date('W', $dataweek);
$year = date('Y', $dataweek);
$timestamp_montag = strtotime("{$year}-W{$kw}");
$timestamp_sonntag = strtotime("{$year}-W{$kw}-7");
$lastdate = strtotime(date("Y-m-d", $timestamp_sonntag) . ' 23:59:59');
$searchArray = ['start' => $timestamp_montag, 'end' => $lastdate];
$daycounter = '0';
$timestamp = $timestamp_montag;
for ($i = 1; $i <= 7; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 2) {
$firstdate = strtotime(date("Y-m-01", $datamonth));
$lastdate = strtotime(date("Y-m-t", $datamonth));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
} else if ($datatype == 3) {
$firstdate = strtotime(date("Y-01-01", $datayear));
$lastdate = strtotime(date("Y-12-31 23:59:59", $datayear));
$daycount = date("t", $datamonth);
$lastdate = strtotime(date("Y-m-d", $lastdate) . ' 23:59:59');
$searchArray = ['start' => $firstdate, 'end' => $lastdate];
$timestamp = $firstdate;
for ($i = 1; $i <= $daycount; $i++) {
$dDate = date('Y-m-d', $timestamp);
$dDay = date('w', $timestamp);
if (!$holiDay[$dDate]) {
$mustSeconds = $mustSeconds + $workingHours[$dDay];
}
$timestamp = $timestamp + 86400;
}
}
$daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
$timerecordingcategories = TimerecordingCategoryModel::getAll();
$timerecordings = TimerecordingModel::search($searchArray);
$responsecount = count($timerecordings);
foreach ($timerecordings as $timerecording):
$state = "";
$enddate = "";
$sum = "-";
$day = "";
$orderdate = $timerecording->start;
if ($timerecording->timerecordingCategory->hourday == 1) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = date("H:i", $timerecording->start);
$end = date("H:i", $timerecording->end);
$seconds = $timerecording->end - $timerecording->start;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
$day = $daysgerm[date("w", $timerecording->start)];
$isSeconds = $isSeconds + $seconds;
} else if ($timerecording->timerecordingCategory->hourday == 2) {
$date = date("d.m.", $timerecording->start) . " - " . $daysgerm[date("w", $timerecording->end)] . " " . date("d.m.Y", $timerecording->end);
$datadate = date("Y-m-d", $timerecording->start);
$enddate = date("Y-m-d", $timerecording->end);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
if ($lastdate < $timerecording->end) {
$endtimecalc = $lastdate;
} else {
$endtimecalc = $timerecording->end;
}
$summcounter = 0;
for ($i = $timerecording->start; $i <= $endtimecalc; $i = $i + 86400) {
$holidaycounter = $workingHours[date("w", $i)];
$isSeconds = $isSeconds + $holidaycounter;
$summcounter = $summcounter + $holidaycounter;
}
$seconds = $summcounter;
$minutes = floor(($seconds % 3600) / 60);
$hours = floor($seconds / 3600);
$sum = sprintf("%02d", $hours) . ":" . sprintf("%02d", $minutes);
} else if ($timerecording->timerecordingCategory->hourday == 3 || $timerecording->timerecordingCategory->hourday == 4) {
$date = date("d.m.Y", $timerecording->start);
$datadate = date("Y-m-d", $timerecording->start);
$start = "-";
$end = "-";
$day = $daysgerm[date("w", $timerecording->start)];
}
if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 0) {
$state = '<i class="fa-regular fa-clock mr-1"></i>';
} else if ($timerecording->timerecordingCategory->approval == 1 && $timerecording->approved == 1) {
$state = '<i class="fa-regular fa-circle-check mr-1"></i>';
}
$edit = "";
if ($timerecording->completed == 0 && $timerecording->timerecordingCategory->only_admin == 0):
if ($timerecording->approved == 0) :
$edit = '<i class="far fa-edit edit-button" data-id="' . $timerecording->id . '"
data-date="' . $datadate . '"
data-category="' . $timerecording->timerecordingCategory->id . '"
data-start="' . $start . '"
data-end="' . $end . '"
data-enddate="' . $enddate . '"
data-comment="' . $timerecording->comment . '"
data-userid="' . $timerecording->user_id . '"
title="Bearbeiten"></i>';
else :
$edit .= '<div class="edit-placeholder"></div>';
endif;
$edit .= '<i data-id="' . $timerecording->id . '" class="fas fa-trash text-danger delete-item" ></i>';
endif;
if ($datatype == 3 && $timerecording->timerecordingCategory->hourday == 1) {
} else {
$rows[] = array(
'user' => array('user' => $timerecording->user->name, 'order' => $timerecording->user->name),
'date' => array('date' => $state . $day . " " . $date, 'order' => $orderdate),
'start' => array('start' => $start, 'order' => $start),
'end' => array('end' => $end, 'order' => $end),
'sum' => array('sum' => $sum, 'order' => $sum),
'category' => array('category' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
'comment' => array('comment' => $timerecording->comment, 'order' => $timerecording->comment),
'edit' => array('edit' => $edit, 'order' => $edit),
);
}
endforeach;
$json['success'] = true;
$json['time']['is'] = sprintf('%02dh:%02dm', floor($isSeconds / 3600), floor($isSeconds / 60 % 60));
$json['time']['must'] = sprintf('%02dh:%02dm', floor($mustSeconds / 3600), floor($mustSeconds / 60 % 60));
$json['time']['holidays'] = $holiDays;
$json['time']['plushours'] = sprintf('%02dh:%02dm', floor($plusHours / 3600), floor($plusHours / 60 % 60));
$json['data'] = $rows;
$json['recordsFiltered'] = $responsecount;
$json['recordsTotal'] = $responsecount;
$json = json_encode($json);
echo trim($json);
die();
}
protected function addAction()

View File

@@ -686,4 +686,8 @@ define("PDFTOTEXT_BIN_PATH", "/usr/bin/pdftotext");
define("TT_MBI_API_ENABLE", true); //Enable API Calls
define("TT_MBI_API_URL", "https://x.x.x.x/api/");
define("TT_MBI_API_VERSION", "v01");
define("TT_MBI_API_KEY", "");
define("TT_MBI_API_KEY", "");
//Raspberry Display Configuration
define("XINON_RASPBERRY_DISPLAY_SSH_USER", "");
define("XINON_RASPBERRY_DISPLAY_SSH_PASS", "");

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingEmployeeAddFields extends AbstractMigration
{
public function up(): void
{
if ($this->getEnvironment() == "thetool") {
$table = $this->table("TimerecordingEmployee", ["signed" => true]);
$table->addColumn("holidays_now", "integer", ["null" => false, "after" => "holidays"]);
$table->addColumn("startdate", "integer", ["null" => false, "after" => "plushours"]);
$table->addColumn("plushours_now", "integer", ["null" => false, "after" => "plushours"]);
$table->update();
}
if ($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if ($this->getEnvironment() == "thetool") {
$this->table("WorkerPermission")->removeColumn("startdate")->save();
$this->table("WorkerPermission")->removeColumn("plushours_now")->save();
$this->table("WorkerPermission")->removeColumn("holidays_now")->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingRenameField extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording");
$table->renameColumn('commend', 'comment')
->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording");
$table->renameColumn('comment', 'commend')
->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingCategoryAddFieldBusinesstrip extends AbstractMigration
{
public function up(): void
{
if ($this->getEnvironment() == "thetool") {
$table = $this->table("TimerecordingCategory", ["signed" => true]);
$table->addColumn("businesstrip", "integer", ["null" => false, "default" => '0', "after" => "only_admin"]);
$table->update();
}
if ($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if ($this->getEnvironment() == "thetool") {
$this->table("TimerecordingCategory")->removeColumn("businesstrip")->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingAddFieldsBusinesstrip extends AbstractMigration
{
public function up(): void
{
if ($this->getEnvironment() == "thetool") {
$table = $this->table("Timerecording", ["signed" => true]);
$table->addColumn("businesstrip", "integer", ["null" => false, "default" => '0', "after" => "timerecordingCategory_id"]);
$table->addColumn("businesstrip_info", "string", ["null" => true, "after" => "businesstrip"]);
$table->update();
}
if ($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if ($this->getEnvironment() == "thetool") {
$this->table("Timerecording")->removeColumn("businesstrip")->save();
$this->table("Timerecording")->removeColumn("businesstrip_info")->save();
}
if ($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class TimerecordingEmployeeAddFieldType extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table("TimerecordingEmployee", ["signed" => true]);
$table->addColumn("type", "integer", ["null" => false, "default" => '1', "after" => "user_id", "comment" => "1:Angestellter/2:Arbeiter/3:Lehrling"]);
$table->update();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table("TimerecordingEmployee")->removeColumn("type")->save();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
use Phinx\Migration\AbstractMigration;
final class AddRaspberryDisplayTable extends AbstractMigration
{
public function up(): void
{
if($this->getEnvironment() == "thetool") {
$table = $this->table('RaspberryDisplay');
$table->addColumn('display_label', 'string', ['limit' => 255])
->addColumn('hostname', 'string', ['limit' => 255])
->addColumn('ip_address', 'string', ['limit' => 15])
->addColumn('display_url', 'string', ['limit' => 255])
->addColumn('auto_refresh_enabled', 'boolean', ['default' => false])
->addColumn('margin_hot_fix_enabled', 'boolean', ['default' => false])
->addColumn('custom_style', 'string', ['limit' => 255, 'null' => true])
->addColumn('create', 'integer', ['null' => true])
->addColumn('edit', 'integer', ['null' => true])
->addColumn('create_by', 'integer', ['null' => true])
->addColumn('edit_by', 'integer', ['null' => true])
->create();
}
if($this->getEnvironment() == "addressdb") {
}
}
public function down(): void
{
if($this->getEnvironment() == "thetool") {
$this->table('RaspberryDisplay')->drop();
}
if($this->getEnvironment() == "addressdb") {
}
}
}

View File

@@ -138,7 +138,7 @@ table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
{
color:#0d6efd;
font-size: 30px;
margin-right:20px;
margin-right:10px;
cursor: pointer;
}
.active-calendar
@@ -216,7 +216,7 @@ table.dataTable.table-sm > thead > tr > th:not(.sorting_disabled) {
{
font-size:35px;
margin-top:5px;
margin-right:30px;
margin-right:10px;
margin-bottom:20px;
}

View File

@@ -38,7 +38,14 @@ $('#filterrow th').each(function (i) {
});
table = $('#datatable').DataTable({
responsive: true,
responsive: {
breakpoints: [
{name: 'desktop', width: Infinity},
{name: 'tablet', width: 1024},
{name: 'fablet', width: 768},
{name: 'phone', width: 480}
]
},
buttons: [
{
extend: 'excelHtml5',

View File

@@ -0,0 +1,51 @@
[v-cloak] {
display: none !important;
}
.display-grid {
display: grid;
grid-template-columns: repeat(8, 11.25vw);
grid-row-gap: 20px;
width: 100vw;
}
.display {
background-color: #f8f9fa;
border: 2px solid #dee2e6;
border-radius: 4px;
overflow: hidden;
font-size: clamp(0.6rem, 0.8rem, 1.1rem);
display: grid;
grid-template-rows: repeat(3, 1fr);
justify-items: center;
}
.display > *:nth-child(1) {
align-self: start;
}
.display > *:nth-child(2) {
align-self: center;
}
.display > *:nth-child(3) {
align-self: end;
}
.small-27-inch {
grid-column: span 1;
margin: 0 0.37vw;
width: calc(10.5vw);
height: calc(10.5vw * 9 / 16)
}
.big-42-inch {
grid-column: span 2;
margin: 0 0.37vw;
width: calc(21vw);
height: calc(21vw * 9 / 16)
}
label {
margin: 0;
}

View File

@@ -0,0 +1,63 @@
// noinspection JSJQueryEfficiency
Vue.filter('cleanupURL', function (value) {
value = value.replace(/^(?:https?:\/\/)?(?:www\.)?/i, "").split('/')[0];
return value;
})
new Vue({
el: '#app',
mounted() {
this.fetchDisplays()
},
methods: {
async rebootRaspberry(displayID) {
this.loading = true;
await axios.get(`${window['TT_CONFIG']["BASE_URL"]}/api?do=reboot`, {
params: {
displayID: displayID
}
});
this.loading = false;
},
async fetchDisplays() {
this.loading = true;
const response = await axios.get(`${window['TT_CONFIG']["BASE_URL"]}/api?do=getDisplays`);
this.displays = response.data.result;
this.loading = false;
Vue.nextTick(() => {
$('[data-toggle="tooltip"]').tooltip('dispose');
$('[data-toggle="tooltip"]').tooltip();
});
},
enableDisplayURLEditMode(displayID) {
this.displaysURLEditMode = displayID;
const _this = this;
// wait for the DOM to update
Vue.nextTick(() => {
_this.$refs['displayURLEditInput'][0].focus();
});
},
disableDisplayURLEditMode(displayID, displayURL) {
this.displaysURLEditMode = null;
this.submitChanges(displayID, 'display_url', displayURL);
},
async submitChanges(displayID, field, value) {
this.loading = true;
await axios.get(`${window['TT_CONFIG']["BASE_URL"]}/api?do=change`, {
params: {
displayID: displayID,
field: field,
value: value,
}
});
await this.fetchDisplays();
this.loading = false;
}
},
data: {
loading: false,
displaysURLEditMode: null,
displays: null,
}
});

View File

@@ -19,6 +19,7 @@ if (typeof columnfilter === "undefined") {
var columnfilter;
columnfilter = "";
}
if (typeof columnoptions === "undefined") {
var columnoptions;
columnoptions = "";
@@ -78,10 +79,13 @@ table = $('#datatable').DataTable({
d.dataweek = $('#dataweek').val();
d.datamonth = $('#datamonth').val();
d.datayear = $('#datayear').val();
},
"dataSrc": function (json) {
$('#is-time').text(json.time.is);
$('#must-time').text(json.time.must);
$('#holidays').text(json.time.holidays);
$('#plushours').text(json.time.plushours);
return json.data;
}
@@ -120,8 +124,8 @@ table = $('#datatable').DataTable({
}
, {
"data": {
_: "commend.commend",
"sort": "commend.order"
_: "comment.comment",
"sort": "comment.order"
},
className: "text-center"
}, {
@@ -206,9 +210,9 @@ $(document).ready(function () {
})
}
if (parseInt($(this).find(':selected').data('comment')) === 1) {
$('#commend').prop("required", true);
$('#comment').prop("required", true);
} else {
$('#commend').prop("required", false);
$('#comment').prop("required", false);
}
});
$("body").on("change", "#date", function () {
@@ -216,6 +220,8 @@ $(document).ready(function () {
if ($('#date').val() > $('#enddate').val()) {
$('#enddate').prop("min", $('#date').val());
$('#enddate').val($('#date').val());
} else {
$('#enddate').prop("min", $('#date').val());
}
}
});
@@ -237,7 +243,7 @@ $(document).ready(function () {
$('#start').val($(this).data('start'));
$('#end').val($(this).data('end'));
$('#enddate').val($(this).data('enddate'));
$('#commend').val($(this).data('commend'));
$('#comment').val($(this).data('comment'));
$('.alert-success').remove();
window.scrollTo(0, 0);
});
@@ -248,7 +254,7 @@ $(document).ready(function () {
$('#id').val('');
});
$("body").on("change", "#dataweek,#datamonth", function () {
$("body").on("change", "#dataweek,#datamonth,#datayear", function () {
table.ajax.reload();
});
$("body").on("click", ".display-calendar", function () {
@@ -258,15 +264,36 @@ $(document).ready(function () {
$(this).addClass('active-calendar');
if ($(this).data('datatype') == "1") {
console.log($(this).data('datatype'));
$('#dataweek-col').show();
$('#dynamictime-div').show();
$('#datamonth-col').hide();
$('#datayear-col').hide();
} else if ($(this).data('datatype') == "2") {
$('#datamonth-col').show();
$('#dynamictime-div').show();
$('#dataweek-col').hide();
$('#datayear-col').hide();
} else if ($(this).data('datatype') == "3") {
$('#datayear-col').show();
$('#dynamictime-div').hide();
$('#datamonth-col').hide();
$('#dataweek-col').hide();
}
$(".select2").select2();
table.ajax.reload();
});
$("body").on("click", "#businesstrip", function () {
if ($(this).prop('checked') == true) {
$('#businesstrip_info').show();
$('#businesstrip_info').prop('required', true);
} else {
$('#businesstrip_info').hide();
$('#businesstrip_info').val('');
$('#businesstrip_info').prop('required', false);
}
});
$("body").on("click", ".delete-item", function () {
if (confirm('Buchung wirklich löschen?')) {
@@ -274,11 +301,10 @@ $(document).ready(function () {
id: $.trim($(this).data('id')),
ajax: 1
}).done(function (data) {
table.ajax.reload();
});
}
})
});
$('form').submit(function (e) {
e.preventDefault();
@@ -290,7 +316,7 @@ $(document).ready(function () {
enddate: $.trim($('#enddate').val()),
start: $.trim($('#start').val()),
end: $.trim($('#end').val()),
commend: $.trim($('#commend').val()),
comment: $.trim($('#comment').val()),
ajax: 1
}).done(function (data) {
var result = $.parseJSON(data);

View File

@@ -0,0 +1,360 @@
let table;
if (typeof hidesearch === "undefined") {
var hidesearch;
hidesearch = [100];
}
if (typeof cstmdom === "undefined") {
var cstmdom;
cstmdom = "flBrtip";
}
if (typeof columndefs === "undefined") {
var columndefs;
columndefs = "";
}
if (typeof columnfilter === "undefined") {
var columnfilter;
columnfilter = "";
}
if (typeof columnoptions === "undefined") {
var columnoptions;
columnoptions = "";
}
$('#filterrow th').each(function (i) {
let title = $('#datatable thead th').eq($(this).index()).text();
if (hidesearch.includes($(this).index())) {
} else if (columnfilter.includes($(this).index())) {
$(this).html('<select style="padding: 0;height: 28px;;text-align: center;" id="selectsearch" class="form-control form-control-select form-control-special" data-index="' + i + '">' + columnoptions + '</select>');
} else {
$(this).html('<input type="text" placeholder="' + title + '" class="form-control" data-index="' + i + '" value="" />');
}
});
table = $('#datatable').DataTable({
responsive: true,
"order": [[1, "desc"]],
buttons: [
{
extend: 'excelHtml5',
text: 'XLSX Export',
className: 'btn-success margina d-none d-lg-block',
exportOptions: {
columns: ['th:not(:last-child)']
}
}
], columnDefs: [
columndefs
],
"language": {
"url": "/datatables/json/german.json?v1"
},
orderCellsTop: true,
stateSave: true,
"initComplete": function () {
$('#datatable_filter').append('<i id="clear_cookie" class="fas fa-times clear-fa" title="Filter löschen" aria-hidden="true" ></i>');
$('#clear_cookie').click(function () {
$('#filterrow input').val('');
$('#filterrow select').val('');
table.search('').columns().search('').draw();
});
},
"dom": cstmdom,
"ajax": {
"url": requestUrl,
"type": "GET",
"data": function (d) {
$('.display-calendar').each(function (index) {
if ($(this).hasClass('active-calendar')) {
d.datatype = $(this).data('datatype');
}
})
d.dataweek = $('#dataweek').val();
d.datamonth = $('#datamonth').val();
d.datayear = $('#datayear').val();
},
"dataSrc": function (json) {
$('#is-time').text(json.time.is);
$('#must-time').text(json.time.must);
$('#holidays').text(json.time.holidays);
$('#plushours').text(json.time.plushours);
return json.data;
}
},
"columns": [
{
"data": {
_: "user.user",
"sort": "user.order"
},
className: "text-nowrap"
},
{
"data": {
_: "date.date",
"sort": "date.order"
},
className: "text-nowrap"
}, {
"data": {
_: "start.start",
"sort": "start.order"
},
className: "text-center"
}, {
"data": {
_: "end.end",
"sort": "end.order"
},
className: "text-center"
}, {
"data": {
_: "sum.sum",
"sort": "sum.order"
},
className: "text-center"
}, {
"data": {
_: "category.category",
"sort": "category.order"
},
className: ""
}
, {
"data": {
_: "comment.comment",
"sort": "comment.order"
},
className: "text-center"
}, {
"data": {
_: "edit.edit",
"sort": "edit.order"
},
className: "edit-td"
}
]
});
$('#filterrow').on('keyup', 'input', function () {
table
.column($(this).data('index'))
.search(this.value)
.draw();
});
$('#selectsearch').change(function () {
table
.column($(this).data('index'))
.search(this.value)
.draw();
});
let state = table.state.loaded();
if (state) {
table.columns().eq(0).each(function (colIdx) {
var colSearch = state.columns[colIdx].search;
if (colSearch.search) {
$('#filterrow').find("[data-index='" + colIdx + "']").val(colSearch.search);
}
});
table.draw();
}
$(document).ready(function () {
$(".select2").select2();
$("body").on("change", "#timerecordingCategory_id", function () {
if (parseInt($(this).find(':selected').data('hourday')) === 2) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
});
$("#enddate-div").show();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", true);
$(this).prop("min", $('#date').val());
$(this).val($('#date').val());
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 1) {
$("#endtime-div").show();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", true);
$(this).prop("disabled", false);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
} else if (parseInt($(this).find(':selected').data('hourday')) === 3 || parseInt($(this).find(':selected').data('hourday')) === 4) {
$("#endtime-div").hide();
$("#endtime-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("disabled", true);
});
$("#enddate-div").hide();
$("#enddate-div").find('input').each(function () {
$(this).prop("required", false);
$(this).prop("min", '');
$(this).val('');
})
}
if (parseInt($(this).find(':selected').data('comment')) === 1) {
$('#comment').prop("required", true);
} else {
$('#comment').prop("required", false);
}
});
$("body").on("change", "#date", function () {
if ($('#enddate-div').css('display') === "block") {
if ($('#date').val() > $('#enddate').val()) {
$('#enddate').prop("min", $('#date').val());
$('#enddate').val($('#date').val());
} else {
$('#enddate').prop("min", $('#date').val());
}
}
});
$("body").on("change", "#start", function () {
if ($('#start').val() > $('#end').val()) {
$('#end').val($('#start').val());
}
$('#end').prop("min", $('#start').val());
});
$("body").on("click", ".edit-button", function () {
$('#submit-button').hide().removeClass('btn-primary').addClass('btn-danger').show();
$('#submit-button').text('Ändern');
$('#cancel-button').show();
$('#timerecordingCategory_id').val($(this).data('category')).change();
$('#user_id_select').prop('disabled', true);
$('#user_id_input').prop('disabled', false);
$('#user_id_select').val($(this).data('userid')).change();
$('#user_id_input').val($(this).data('userid'));
$('#id').val($(this).data('id'));
$('#date').val($(this).data('date'));
$('#start').val($(this).data('start'));
$('#end').val($(this).data('end'));
$('#enddate').val($(this).data('enddate'));
$('#comment').val($(this).data('comment'));
$('.alert-success').remove();
window.scrollTo(0, 0);
});
$("body").on("click", "#cancel-button", function () {
$('#submit-button').text('Speichern');
$('#cancel-button').hide();
$('#user_id_select').prop('disabled', false);
$('#user_id_input').prop('disabled', true);
$('#user_id_select').change();
$('#timerecordingCategory_id').val($(this).data('category')).change();
$('#id').val('');
});
$("body").on("change", "#dataweek,#datamonth,#datayear", function () {
table.ajax.reload(null, false);
});
$("body").on("click", ".display-calendar", function () {
$('.display-calendar').each(function (index) {
$(this).removeClass('active-calendar');
});
$(this).addClass('active-calendar');
if ($(this).data('datatype') == "1") {
$('#dataweek-col').show();
$('#dynamictime-div').show();
$('#datamonth-col').hide();
$('#datayear-col').hide();
} else if ($(this).data('datatype') == "2") {
$('#datamonth-col').show();
$('#dynamictime-div').show();
$('#dataweek-col').hide();
$('#datayear-col').hide();
} else if ($(this).data('datatype') == "3") {
$('#datayear-col').show();
$('#dynamictime-div').hide();
$('#datamonth-col').hide();
$('#dataweek-col').hide();
}
$(".select2").select2();
table.ajax.reload(null, false);
});
$("body").on("click", ".delete-item", function () {
if (confirm('Buchung wirklich löschen?')) {
$.post(deleteUrl, {
id: $.trim($(this).data('id')),
ajax: 1
}).done(function (data) {
table.ajax.reload(null, false);
});
}
})
$('form').submit(function (e) {
e.preventDefault();
$('#alert-box').remove();
var userid;
if ($.trim($('#id').val())) {
userid = $('#user_id_input').val();
}
$.post(insertUrl, {
id: $.trim($('#id').val()),
user_id: userid,
timerecordingCategory_id: $.trim($('#timerecordingCategory_id').val()),
date: $.trim($('#date').val()),
enddate: $.trim($('#enddate').val()),
start: $.trim($('#start').val()),
end: $.trim($('#end').val()),
comment: $.trim($('#comment').val()),
ajax: 1
}).done(function (data) {
var result = $.parseJSON(data);
if (result.state === "success") {
$('.wrapper .container-fluid').prepend(`<div id="alert-box" class="row">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h5><i class="icon fas fa-check"></i> Erfolgreich</h5>
` + result.message + `</div>
</div>`);
}
if (result.state === "error") {
$('.wrapper .container-fluid').prepend(`<div id="alert-box" class="row">
<div class="col-md-1"></div>
<div class="col-md-10 alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h5><i class="icon fas fa-ban"></i> Fehler</h5>
` + result.error + `</div>
</div>`);
}
$('#submit-button').hide().removeClass('btn-danger').addClass('btn-primary').show();
$('#submit-button').text('Speichern');
$('#cancel-button').hide();
$('#user_id_select').prop('disabled', false);
$('#user_id_input').prop('disabled', true);
$('#user_id_select').change();
$('#id').val('');
table.ajax.reload(null, false);
});
});
})
;

2
public/plugins/axios/axios.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,45 @@
# TheTool Vue Frontend Framework
## Components
### tt-page-title
The `tt-page-title` is used to create the Title and breadcumbs on the top of the page
#### Props
- `title`: String - The title of the current page. This will be displayed prominently at the top of the breadcrumb navigation bar.
- `path`: Array - An array of objects representing the breadcrumb path. Each object in the array should have the following properties:
- `text`: String - The display text for the breadcrumb item.
- `href`: String - The URL that the breadcrumb item links to.
#### Usage
Include the Component on the View
```php
$additionalJS = ["plugins/vue/tt-components/tt-page-title.js"];
```
Then use it inside the Vue App
```vue
<tt-page-title :title="'Your Page Title'" :path="[
{ text: 'Home', href: '/' },
{ text: 'Library', href: '/library' },
{ text: 'Data', href: '/library/data' } // Current Page
]"></tt-page-title>
```
### tt-loader
The `tt-loader` is used to display a loader
#### Usage
Include the Component on the View
```php
$additionalJS = ["plugins/vue/tt-components/tt-loader.js"];
$additionalCSS = ["plugins/vue/tt-components/css/tt-loader.css"];
```
Then use it inside the Vue App in the container where it should get full width
```vue
<tt-loader></tt-loader>

View File

@@ -0,0 +1,25 @@
.overlay {
width: 100%;
height: 100%;
background-color: rgba(10, 10, 10, 0.5); /* Semi-transparent black */
z-index: 9999;
display: flex;
justify-content: center;
align-items: center; /* Center the spinner vertically and horizontally */
position: absolute;
top: 50%;
left: 50%;
opacity: 0.5;
transform: translate(-50%, -50%);
}
/* Define the transition */
.fade-enter-active, .fade-leave-active {
transition: opacity 0.2s ease;
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */
{
opacity: 0;
}

View File

@@ -0,0 +1,15 @@
Vue.component('tt-loader', {
template: `
<transition name="fade">
<div class="w-100 h-100" style="position: absolute;">
<div class="overlay" id="loading">
<div class="d-flex justify-content-center">
<div class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
</div>
</div>
</transition>
`
});

View File

@@ -0,0 +1,19 @@
Vue.component('tt-page-title', {
props: ['title', 'path'],
template: `
<div class="row">
<div class="col-12">
<div class="page-title-box">
<div class="page-title-right">
<ol class="breadcrumb m-0">
<li class="breadcrumb-item" v-for="item in path" :key="item.text">
<a :href="item.href">{{ item.text }}</a>
</li>
</ol>
</div>
<h4 class="page-title">{{ title }}</h4>
</div>
</div>
</div>
`
});

11932
public/plugins/vue/vue.js Normal file

File diff suppressed because it is too large Load Diff

11
public/plugins/vue/vue.min.js vendored Normal file

File diff suppressed because one or more lines are too long