Zeiterfassung update
* Kalender Implementation * Dienstreise Funktionalitäten
This commit is contained in:
@@ -184,9 +184,9 @@ $years[time() - 31536000] = date('Y', time() - 31536000);
|
||||
<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">
|
||||
<input class="form-check-input" type="checkbox" name="businesstrip"
|
||||
id="businesstrip" value="1">
|
||||
<label class="form-check-label" for="businesstrip" >
|
||||
Dienstreise > 12KM
|
||||
</label>
|
||||
</div>
|
||||
|
||||
244
Layout/default/TimerecordingCalendar/Index.php
Normal file
244
Layout/default/TimerecordingCalendar/Index.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/header.php");
|
||||
$daysgerm = array("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa");
|
||||
?>
|
||||
<link href="<?= self::getResourcePath() ?>assets/css/select2-cstm.css?<?= date('U') ?>" rel="stylesheet"
|
||||
type="text/css"/>
|
||||
<style>
|
||||
.fc-toolbar {
|
||||
@media (max-width: 767px) {
|
||||
flex-direction: column;
|
||||
.fc-toolbar-chunk {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fc .fc-button-primary:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.fc .fc-button:focus {
|
||||
box-shadow: none;
|
||||
outline: 0px;
|
||||
}
|
||||
|
||||
.fc .fc-button-primary:not(:disabled).fc-button-active:focus, .fc .fc-button-primary:not(:disabled):active:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript"
|
||||
src="<?= self::getResourcePath() ?>assets/js/calendar/moment/moment.min.js?<?= date('U') ?>"></script>
|
||||
<script type="text/javascript"
|
||||
src="<?= self::getResourcePath() ?>assets/js/calendar/index.global.min.js?<?= date('U') ?>"></script>
|
||||
<script type="text/javascript"
|
||||
src="<?= self::getResourcePath() ?>assets/js/calendar/moment/index.global.min.js?<?= date('U') ?>"></script>
|
||||
<script type="text/javascript"
|
||||
src="<?= self::getResourcePath() ?>assets/js/calendar/locales-all.global.min.js?<?= date('U') ?>"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
let requestUrl = "<?= self::getUrl("TimerecordingReport", "api", ['do' => 'getTimerecordings', 'datatype' => '3', 'datayear' => time()]) ?>";
|
||||
var cindex = 1;
|
||||
var holiDays = [];
|
||||
<?php
|
||||
$counter = 1;
|
||||
foreach ($timerecordingholidays as $timerecordingholiday) :?>
|
||||
holiDays.push({
|
||||
id: <?= $counter ?>,
|
||||
start: '<?= date("Y-m-d", $timerecordingholiday->timestamp) ?>',
|
||||
end: '<?= date("Y-m-d", $timerecordingholiday->timestamp) ?>',
|
||||
title: '<?= $timerecordingholiday->description ?>'
|
||||
});
|
||||
<?php
|
||||
$counter++;
|
||||
endforeach;
|
||||
?>
|
||||
cindex = <?= $counter ?>;
|
||||
console.log(holiDays);
|
||||
$.getJSON(requestUrl, function (data) {
|
||||
|
||||
}).done(function (json) {
|
||||
var bgcolors = ['rgba(251, 71, 71,0.2)', 'rgba(253, 126, 20, 0.25)', 'rgba(91, 71, 251, 0.2)', 'rgba(71, 251, 151, 0.2)', 'rgba(251, 71, 194, 0.2)', 'rgba(20, 251, 253, 0.25)'];
|
||||
//read data from json
|
||||
var json = json.data;
|
||||
var holidays = [];
|
||||
var colorcount = 0;
|
||||
var oldname = "";
|
||||
$.each(json, function (index, value) {
|
||||
if (oldname != value.user.user) {
|
||||
colorcount++;
|
||||
if (colorcount > 5) {
|
||||
colorcount = 0;
|
||||
}
|
||||
oldname = value.user.user;
|
||||
}
|
||||
holidays.push({
|
||||
id: cindex,
|
||||
backgroundColor: bgcolors[colorcount],
|
||||
start: value.cstart.cstart,
|
||||
end: value.cend.cend,
|
||||
title: value.category.category + " " + value.user.user,
|
||||
description: value.category.category + " " + value.user.user
|
||||
});
|
||||
oldname = value.user.user;
|
||||
cindex++;
|
||||
});
|
||||
|
||||
console.log(holidays);
|
||||
|
||||
var initialLocaleCode = 'en';
|
||||
var calendarEl = document.getElementById('fullcalendar');
|
||||
var containerEl = document.getElementById('external-events');
|
||||
var localeSelectorEl = document.getElementById('locale-selector');
|
||||
|
||||
var curYear = '2024';
|
||||
var curMonth = '02';
|
||||
|
||||
// Calendar Event Source
|
||||
|
||||
// Birthday Events Source
|
||||
var birthdayEvents = {
|
||||
id: 1,
|
||||
backgroundColor: 'rgba(255, 0, 0 , 1)',
|
||||
borderColor: 'rgba(255, 0, 0 , 1)',
|
||||
textColor: '#fff',
|
||||
events: holiDays
|
||||
|
||||
};
|
||||
|
||||
|
||||
var holidayEvents = {
|
||||
id: 5,
|
||||
backgroundColor: 'rgba(0,204,204,.25)',
|
||||
borderColor: 'rgb(192 0 255)',
|
||||
textColor: '#000',
|
||||
events: holidays
|
||||
};
|
||||
|
||||
|
||||
var initialLocaleCode = 'en';
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
locale: 'de',
|
||||
headerToolbar: {
|
||||
left: "prev,today,next",
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
|
||||
},
|
||||
editable: true,
|
||||
droppable: true, // this allows things to be dropped onto the calendar
|
||||
fixedWeekCount: true,
|
||||
// height: 300,
|
||||
initialView: 'dayGridMonth',
|
||||
timeZone: 'UTC',
|
||||
hiddenDays: [],
|
||||
navLinks: 'true',
|
||||
events: [],
|
||||
height: 800,
|
||||
eventSources: [holidayEvents, birthdayEvents]
|
||||
});
|
||||
calendar.render();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
<style>
|
||||
.edit-button {
|
||||
color: #007bff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.approved-open {
|
||||
background-color: #fdb751 !important;
|
||||
color: #000;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.approved-closed {
|
||||
background-color: #96ff68 !important;
|
||||
color: #000;
|
||||
border-radius: 5px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.fa-clock {
|
||||
color: #ff9b00;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.edit-placeholder {
|
||||
height: 15px;
|
||||
width: 22px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.fa-square-check {
|
||||
color: #23b900;
|
||||
font-size: 17px;
|
||||
vertical-align: middle;
|
||||
margin-bottom: 2px;
|
||||
margin-right: 3px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<link href="<?= self::getResourcePath() ?>assets/css/datatables-std.css?<?= date('U') ?>" rel="stylesheet"
|
||||
type="text/css"/>
|
||||
<!-- start page title -->
|
||||
<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"><a href="<?= self::getUrl("Dashboard") ?>"><?= MFAPPNAME_SLUG ?></a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">Abwesenheitskalender</li>
|
||||
</ol>
|
||||
</div>
|
||||
<h4 class="page-title">Abwesenheitskalender</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end page title -->
|
||||
<div class="card text-center">
|
||||
<div class="card-body mb-3 ">
|
||||
<div class="row ">
|
||||
<div class="col-12">
|
||||
<div class="float-left">
|
||||
<h4 class="header-title">Abwesenheitskalender</h4>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12 col-lg-10">
|
||||
|
||||
<div id='calendar'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var hidesearch = [2, 3, 4, 8];
|
||||
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 () {
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="<?= self::getResourcePath() ?>assets/js/datatables-std.js?<?= date('U') ?>"></script>
|
||||
|
||||
|
||||
<?php include(realpath(dirname(__FILE__) . "/../../$mfLayoutPackage") . "/footer.php"); ?>
|
||||
@@ -38,7 +38,8 @@
|
||||
<li><a href="<?=self::getUrl("Timerecording")?>"><i class="far fa-fw fa-calendar text-info"></i> Buchungen</a></li>
|
||||
<?php if ($me->can('Fibu')): ?>
|
||||
<li><a href="<?=self::getUrl("TimerecordingPermit")?>"><i class="far fa-fw fa-calendar-check text-info"></i> Freigaben</a></li>
|
||||
<li><a href="<?=self::getUrl("TimerecordingReport")?>"><i class="far fa-fw fa-chart-pie text-info"></i> Auswertungen</a></li>
|
||||
<li><a href="<?=self::getUrl("TimerecordingCalendar")?>"><i class="far fa-fw fa-calendar-days text-info"></i> Abwesenheitskalender</a></li>
|
||||
<li><a href="<?=self::getUrl("TimerecordingReport")?>"><i class="far fa-fw fa-chart-pie text-info"></i> Auswertung/Korrektur</a></li>
|
||||
<li><a href="<?=self::getUrl("TimerecordingCategory")?>"><i class="far fa-fw fa-list text-info"></i> Buchungsarten</a></li>
|
||||
<li><a href="<?=self::getUrl("TimerecordingHoliday")?>"><i class="far fa-fw fa-umbrella-beach text-info"></i> Feiertage</a></li>
|
||||
<li><a href="<?=self::getUrl("TimerecordingEmployee")?>"><i class="far fa-fw fa-user text-info"></i> Personaladministration</a></li>
|
||||
|
||||
@@ -150,6 +150,22 @@ class TimerecordingController extends mfBaseController
|
||||
$data['end'] = $endtime;
|
||||
$data['timerecordingCategory_id'] = trim($r->timerecordingCategory_id);
|
||||
$data['comment'] = trim($r->comment);
|
||||
$data['businesstrip'] = $r->businesstrip;
|
||||
$data['businesstrip_info'] = $r->businesstrip_info;
|
||||
|
||||
if (!$data['businesstrip'] || $data['businesstrip'] == "false") {
|
||||
$data['businesstrip'] = 0;
|
||||
}
|
||||
if ($r->businesstrip == 1 && !$r->businesstrip_info) {
|
||||
$result['state'] = "error";
|
||||
$result['error'] = "Geschäftsreiseinformationen darf nicht leer sein";
|
||||
echo json_encode($result);
|
||||
die();
|
||||
}
|
||||
if (!$data['businesstrip_info']) {
|
||||
$data['businesstrip_info'] = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (!$data['user_id']) {
|
||||
$this->layout()->setFlash("Benutzer darf nicht leer sein", "error");
|
||||
|
||||
@@ -6,6 +6,8 @@ class TimerecordingModel
|
||||
private $start;
|
||||
private $end;
|
||||
private $timerecordingCategory_id;
|
||||
private $businesstrip;
|
||||
private $businesstrip_info;
|
||||
private $comment;
|
||||
private $approved;
|
||||
private $completed;
|
||||
@@ -122,7 +124,7 @@ class TimerecordingModel
|
||||
$items = [];
|
||||
$db = FronkDB::singleton();
|
||||
$where = self::getSqlFilter($filter);
|
||||
$res = $db->select("Timerecording", "*", "$where");
|
||||
$res = $db->select("Timerecording", "*", "$where ");
|
||||
if ($db->num_rows($res)) {
|
||||
while ($data = $db->fetch_object($res)) {
|
||||
$items[] = new Timerecording($data);
|
||||
@@ -133,7 +135,7 @@ class TimerecordingModel
|
||||
|
||||
private static function getSqlFilter($filter)
|
||||
{
|
||||
$where = "1=1 ";
|
||||
$where = "1=1";
|
||||
|
||||
if (array_key_exists("user_id", $filter)) {
|
||||
$userid = $filter['user_id'];
|
||||
@@ -145,7 +147,7 @@ class TimerecordingModel
|
||||
$start = $filter['start'];
|
||||
$end = $filter['end'];
|
||||
if (is_numeric($start) && is_numeric($end)) {
|
||||
$where .= " AND `start` > $start AND `start` < $end";
|
||||
$where .= " AND `start` > $start AND `start` < $end ORDER by user_id ASC";
|
||||
}
|
||||
}
|
||||
if (array_key_exists("starttime", $filter) && array_key_exists("endtime", $filter)) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class TimerecordingCalendarController extends mfBaseController
|
||||
{
|
||||
|
||||
protected function init()
|
||||
{
|
||||
$this->needlogin = true;
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
$this->me = $me;
|
||||
$this->layout()->set("me", $me);
|
||||
|
||||
if (!$me->can(["Fibu"])) {
|
||||
$this->redirect("Dashboard");
|
||||
}
|
||||
}
|
||||
|
||||
protected function indexAction()
|
||||
{
|
||||
$timerecordingholidays = TimerecordingHolidayModel::getAll();
|
||||
$this->layout()->set("timerecordingholidays", $timerecordingholidays);
|
||||
$this->layout()->setTemplate("TimerecordingCalendar/Index");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -226,6 +226,8 @@ class TimerecordingReportController extends mfBaseController
|
||||
'start' => array('start' => $start, 'order' => $start),
|
||||
'end' => array('end' => $end, 'order' => $end),
|
||||
'sum' => array('sum' => $sum, 'order' => $sum),
|
||||
'cstart' => array('cstart' => $datadate, 'order' => $datadate),
|
||||
'cend' => array('cend' => $enddate, 'order' => $enddate),
|
||||
'category' => array('category' => $timerecording->timerecordingCategory->name, 'order' => $timerecording->timerecordingCategory->name),
|
||||
'comment' => array('comment' => $timerecording->comment, 'order' => $timerecording->comment),
|
||||
'edit' => array('edit' => $edit, 'order' => $edit),
|
||||
|
||||
6
public/assets/js/calendar/index.global.min.js
vendored
Normal file
6
public/assets/js/calendar/index.global.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
public/assets/js/calendar/moment/index.global.min.js
vendored
Normal file
6
public/assets/js/calendar/moment/index.global.min.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
FullCalendar Moment Plugin v6.1.10
|
||||
Docs & License: https://fullcalendar.io/docs/moment-plugin
|
||||
(c) 2023 Adam Shaw
|
||||
*/
|
||||
FullCalendar.Moment=function(e,t,l,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}var r=a(l);function u(e,t,l,n){let a;return"local"===t?a=r.default(e):"UTC"===t?a=r.default.utc(e):r.default.tz?a=r.default.tz(e,t):(a=r.default.utc(e),null!=l&&a.utcOffset(l)),a.locale(n),a}function o(e){return t=>t?e.format(t):""}var d=t.createPlugin({name:"@fullcalendar/moment",cmdFormatter:function(e,t){let l=function e(t){let l=t.match(/^(.*?)\{(.*)\}(.*)$/);if(l){let t=e(l[2]);return{head:l[1],middle:t,tail:l[3],whole:l[1]+t.whole+l[3]}}return{head:null,middle:null,tail:null,whole:t}}(e);if(t.end){let e=u(t.start.array,t.timeZone,t.start.timeZoneOffset,t.localeCodes[0]),n=u(t.end.array,t.timeZone,t.end.timeZoneOffset,t.localeCodes[0]);return function e(t,l,n,a){if(t.middle){let r=l(t.head),u=e(t.middle,l,n,a),o=l(t.tail),d=n(t.head),i=e(t.middle,l,n,a),f=n(t.tail);if(r===d&&o===f)return r+(u===i?u:u+a+i)+o}let r=l(t.whole),u=n(t.whole);if(r===u)return r;return r+a+u}(l,o(e),o(n),t.defaultSeparator)}return u(t.date.array,t.timeZone,t.date.timeZoneOffset,t.localeCodes[0]).format(l.whole)}});return t.globalPlugins.push(d),e.default=d,e.toMoment=function(e,t){if(!(t instanceof n.CalendarImpl))throw new Error("must supply a CalendarApi instance");let{dateEnv:l}=t.getCurrentData();return u(e,l.timeZone,null,l.locale.codes[0])},e.toMomentDuration=function(e){return r.default.duration(e)},Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,moment,FullCalendar.Internal);
|
||||
2
public/assets/js/calendar/moment/moment.min.js
vendored
Normal file
2
public/assets/js/calendar/moment/moment.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -214,6 +214,18 @@ $(document).ready(function () {
|
||||
} else {
|
||||
$('#comment').prop("required", false);
|
||||
}
|
||||
|
||||
if (parseInt($(this).find(':selected').data('businesstrip')) === 1) {
|
||||
$('#businesstrip-div').show();
|
||||
$('#businesstrip').prop("checked", false);
|
||||
$('#businesstrip_info').val('');
|
||||
$('#businesstrip_info').hide();
|
||||
} else {
|
||||
$('#businesstrip-div').hide();
|
||||
$('#businesstrip').prop("checked", false);
|
||||
$('#businesstrip_info').val('');
|
||||
$('#businesstrip_info').hide();
|
||||
}
|
||||
});
|
||||
$("body").on("change", "#date", function () {
|
||||
if ($('#enddate-div').css('display') === "block") {
|
||||
@@ -309,6 +321,10 @@ $(document).ready(function () {
|
||||
$('form').submit(function (e) {
|
||||
e.preventDefault();
|
||||
$('#alert-box').remove();
|
||||
var businesstrip = false;
|
||||
if ($('#businesstrip').prop('checked') == true) {
|
||||
businesstrip = 1;
|
||||
}
|
||||
$.post(insertUrl, {
|
||||
id: $.trim($('#id').val()),
|
||||
timerecordingCategory_id: $.trim($('#timerecordingCategory_id').val()),
|
||||
@@ -317,6 +333,8 @@ $(document).ready(function () {
|
||||
start: $.trim($('#start').val()),
|
||||
end: $.trim($('#end').val()),
|
||||
comment: $.trim($('#comment').val()),
|
||||
businesstrip: businesstrip,
|
||||
businesstrip_info: $.trim($('#businesstrip_info').val()),
|
||||
ajax: 1
|
||||
}).done(function (data) {
|
||||
var result = $.parseJSON(data);
|
||||
@@ -328,6 +346,10 @@ $(document).ready(function () {
|
||||
<h5><i class="icon fas fa-check"></i> Erfolgreich</h5>
|
||||
` + result.message + `</div>
|
||||
</div>`);
|
||||
$('#businesstrip').prop('checked', false);
|
||||
$('#businesstrip_info').hide();
|
||||
$('#businesstrip_info').val('');
|
||||
$('#businesstrip_info').prop('required', false);
|
||||
}
|
||||
if (result.state === "error") {
|
||||
$('.wrapper .container-fluid').prepend(`<div id="alert-box" class="row">
|
||||
|
||||
Reference in New Issue
Block a user