OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)

This commit is contained in:
wangruiguo
2026-09-03 18:49:20 +08:00
commit d647428529
3501 changed files with 1988906 additions and 0 deletions

View File

@@ -0,0 +1,205 @@
@extends($layout)
@section('content')
@php
$values = $values ?? [];
@endphp
<div class="pageheader">
<form action="index.php?act=tickets.showAll" method="post" class="searchbar">
<x-global::forms.text-input name="term"
placeholder="{{ __('input.placeholders.search_type_hit_enter') }}" />
</form>
<div class="pageicon"><span class="fa-laptop"></span></div>
<div class="pagetitle">
<h5>{!! __('OVERVIEW') !!}</h5>
<h1>{!! __('MY_TIMESHEETS') !!}</h1>
</div>
</div><!--pageheader-->
<div class="maincontent">
<div class="maincontentinner">
<div class="fail">
@if (($info ?? '') != '')
<span class="info">{!! $tpl->displayNotification() !!}</span>
@endif
</div>
<div id="loader">&nbsp;</div>
<form action="" method="post" class="stdform">
<div class="row-fluid">
<div class="span12">
<div class="widget">
<h4 class="widgettitle">{!! __('OVERVIEW') !!}</h4>
<div class="widgetcontent" style="min-height: 460px">
<label for="clients">{!! __('label.client') !!}</label>
<select name="clients" id="clients" onchange="filterProjectsByClient();">
<option value="all">{!! __('headline.all_clients') !!}</option>
@foreach ($allClients as $client)
<option value="{{ $client['id'] }}">{{ $client['name'] }}</option>
@endforeach
</select> <br/>
<label for="projects">{!! __('PROJECT') !!}</label> <select
name="projects" id="projects"
onchange="removeOptions($('select#projects option:selected').val());">
<option value="all">{!! __('ALL_PROJECTS') !!}</option>
<optgroup>
@php $lastClientName = ''; @endphp
@foreach ($allProjects as $row)
@php $currentClientName = $row['clientName']; @endphp
@if ($currentClientName != $lastClientName)
</optgroup><optgroup label="{{ $currentClientName }}">
@endif
<option value="{{ $row['id'] }}" data-client-id="{{ $row['clientId'] }}"
@if ($row['id'] == $values['project'])
selected="selected"
@endif
>{{ $row['name'] }}</option>
@php $lastClientName = $row['clientName']; @endphp
@endforeach
</optgroup>
</select> <br/>
<label for="tickets">{!! __('TICKET') !!}</label>
<select name="tickets" id="tickets">
@foreach ($allTickets as $row)
<option class="{{ $row['projectId'] }}" value="{{ $row['projectId'] }}|{{ $row['id'] }}"
@if ($row['id'] == $values['ticket'])
selected="selected"
@endif
>{{ $row['headline'] }}</option>
@endforeach
</select> <br/>
<br/>
<label for="kind">{!! __('KIND') !!}</label> <select id="kind"
name="kind">
@foreach ($kind as $row)
<option value="{{ $row }}"
@if ($row == $values['kind'])
selected="selected"
@endif
>{!! __($row) !!}</option>
@endforeach
</select><br/>
<label for="date">{!! __('DATE') !!}</label> <input type="text" autocomplete="off"
id="date" name="date"
value="{{ $values['date'] }}"
size="7"/>
<br/>
<label for="hours">{!! __('HOURS') !!}</label> <x-global::forms.text-input
id="hours" name="hours"
value="{{ $values['hours'] }}" size="7" /> <br/>
<label for="description">{!! __('DESCRIPTION') !!}</label> <x-global::forms.textarea
rows="5" cols="50" id="description"
name="description">{{ $values['description'] }}</x-global::forms.textarea><br/>
<br/>
<br/>
<label for="invoicedEmpl">{!! __('INVOICED') !!}</label> <input
type="checkbox" name="invoicedEmpl" id="invoicedEmpl"
@if (isset($values['invoicedEmpl']) && $values['invoicedEmpl'] == '1')
checked="checked"
@endif />
{!! __('ONDATE') !!}&nbsp;<input type="text"
id="invoicedEmplDate" name="invoicedEmplDate"
value="{{ $values['invoicedEmplDate'] }}"
size="7"/><br/>
@if ($login::userIsAtLeast($roles::$manager))
<br/>
<label for="invoicedComp">{!! __('INVOICED_COMP') !!}</label> <input
type="checkbox" name="invoicedComp" id="invoicedComp"
@if ($values['invoicedComp'] == '1')
checked="checked"
@endif />
{!! __('ONDATE') !!}&nbsp;<input type="text" autocomplete="off"
id="invoicedCompDate"
name="invoicedCompDate"
value="{{ $values['invoicedCompDate'] }}"
size="7"/><br/>
<label for="paid">{!! __('labels.paid') !!}</label> <input
type="checkbox" name="paid" id="paid"
@if ($values['paid'] == '1')
checked="checked"
@endif />
{!! __('ONDATE') !!}&nbsp;<input type="text" autocomplete="off"
id="paidDate"
name="paidDate"
value="{{ $values['paidDate'] }}"
size="7"/><br/>
@endif <x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('SAVE')" name="save" /> <x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('SAVE_NEW')" name="saveNew" />
</form>
</div>
</div>
@once
@push('scripts')
<script type="text/javascript">
function filterProjectsByClient() {
var selectedClientId = jQuery('#clients option:selected').val();
var projectSelect = jQuery('#projects');
// Show all projects if "all" is selected
if (selectedClientId === 'all') {
projectSelect.find('option').show();
projectSelect.find('optgroup').show();
} else {
// Hide all options first
projectSelect.find('option[data-client-id]').hide();
projectSelect.find('optgroup').hide();
// Show only projects matching the selected client
projectSelect.find('option[data-client-id="' + selectedClientId + '"]').show();
projectSelect.find('option[data-client-id="' + selectedClientId + '"]').parent('optgroup').show();
}
// Reset project selection to "all"
projectSelect.val('all');
}
jQuery("#date, #invoicedCompDate, #invoicedEmplDate, #paidDate").datepicker({
dateFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "jquery"),
dayNames: leantime.i18n.__("language.dayNames").split(","),
dayNamesMin: leantime.i18n.__("language.dayNamesMin").split(","),
dayNamesShort: leantime.i18n.__("language.dayNamesShort").split(","),
monthNames: leantime.i18n.__("language.monthNames").split(","),
currentText: leantime.i18n.__("language.currentText"),
closeText: leantime.i18n.__("language.closeText"),
buttonText: leantime.i18n.__("language.buttonText"),
isRTL: leantime.i18n.__("language.isRTL") === "true" ? 1 : 0,
nextText: leantime.i18n.__("language.nextText"),
prevText: leantime.i18n.__("language.prevText"),
weekHeader: leantime.i18n.__("language.weekHeader"),
firstDay: leantime.i18n.__("language.firstDayOfWeek"),
});
</script>
@endpush
@endonce
@endsection

View File

@@ -0,0 +1,13 @@
@extends($layout)
@section('content')
<h4 class="widgettitle title-light">{!! __('headlines.delete_time') !!}</h4>
<form method="post" action="{{ BASE_URL }}/timesheets/delTime/{{ $id }}">
<p>{!! __('text.confirm_delete_timesheet') !!}</p><br />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.yes_delete')" name="del" />
<x-global::forms.button tag="a" contentRole="tertiary" link="{{ session('lastPage') }}">{!! __('buttons.back') !!}</x-global::forms.button>
</form>
@endsection

View File

@@ -0,0 +1,184 @@
@php
use Leantime\Core\Support\FromFormat;
@endphp
<script type="text/javascript">
function filterProjectsByClient() {
var selectedClientId = jQuery('#clients option:selected').val();
var projectSelect = jQuery('#projects');
// Show all projects if "all" is selected
if (selectedClientId === 'all') {
projectSelect.find('option').show();
} else {
// Hide all options first (except the "all" option)
projectSelect.find('option[data-client-id]').hide();
// Show only projects matching the selected client
projectSelect.find('option[data-client-id="' + selectedClientId + '"]').show();
}
// Reset project selection to "all" and trigger chosen update
projectSelect.val('all');
projectSelect.trigger("chosen:updated");
}
jQuery(document).ready(function() {
jQuery(".client-select").chosen();
jQuery(".project-select").chosen();
jQuery(".ticket-select").chosen();
jQuery(".project-select").change(function () {
jQuery(".ticket-select").removeAttr("selected");
jQuery(".ticket-select").val("");
jQuery(".ticket-select").trigger("liszt:updated");
jQuery(".ticket-select option").show();
jQuery("#ticketSelect .chosen-results li").show();
var selectedValue = jQuery(this).find("option:selected").val();
jQuery("#ticketSelect .chosen-results li").not(".project_" + selectedValue).hide();
});
jQuery(".ticket-select").change(function () {
var selectedValue = jQuery(this).find("option:selected").attr("data-value");
jQuery(".project-select option[value=" + selectedValue + "]").attr("selected", "selected");
jQuery(".project-select").trigger("liszt:updated");
});
jQuery(document).ready(function ($) {
jQuery("#datepicker, #date, #invoicedCompDate, #invoicedEmplDate, #paidDate").datepicker({
numberOfMonths: 1,
dateFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "jquery"),
dayNames: leantime.i18n.__("language.dayNames").split(","),
dayNamesMin: leantime.i18n.__("language.dayNamesMin").split(","),
dayNamesShort: leantime.i18n.__("language.dayNamesShort").split(","),
monthNames: leantime.i18n.__("language.monthNames").split(","),
currentText: leantime.i18n.__("language.currentText"),
closeText: leantime.i18n.__("language.closeText"),
buttonText: leantime.i18n.__("language.buttonText"),
isRTL: leantime.i18n.__("language.isRTL") === "true" ? 1 : 0,
nextText: leantime.i18n.__("language.nextText"),
prevText: leantime.i18n.__("language.prevText"),
weekHeader: leantime.i18n.__("language.weekHeader"),
});
});
});
</script>
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light"><span class="fa-regular fa-clock"></span> {!! __('headlines.edit_time') !!}</h4>
<form action="{{ BASE_URL }}/timesheets/editTime/{{ (int) $_GET['id'] }}" method="post" class="editTimeModal">
<label for="clients">{!! __('label.client') !!}</label>
<select name="clients" id="clients" class="client-select" onchange="filterProjectsByClient();">
<option value="all">{!! __('headline.all_clients') !!}</option>
@foreach ($allClients as $client)
<option value="{{ $client['id'] }}">{{ $client['name'] }}</option>
@endforeach
</select> <br />
<label for="projects">{!! __('label.project') !!}</label>
<select name="projects" id="projects" class="project-select">
<option value="all">{!! __('headline.all_projects') !!}</option>
@foreach ($allProjects as $row)
<option value="{{ $row['id'] }}" data-client-id="{{ $row['clientId'] }}"
@if ($row['id'] == $values['project'])
selected="selected"
@endif
>{{ $row['name'] }}</option>
@endforeach
</select> <br />
<div id="ticketSelect">
<label for="tickets">{!! __('label.ticket') !!}</label>
<select name="tickets" id="tickets" class="ticket-select">
@foreach ($allTickets as $row)
<option class="project_{{ $row['projectId'] }}" data-value="{{ $row['projectId'] }}" value="{{ $row['id'] }}"
@if ($row['id'] == $values['ticket'])
selected="selected"
@endif
>{{ $row['headline'] }}</option>
@endforeach
</select> <br />
</div>
<label for="kind">{!! __('label.kind') !!}</label> <select id="kind"
name="kind">
@foreach ($kind as $key => $row)
<option value="{{ $key }}"
@if ($key == $values['kind'])
selected="selected"
@endif
>{!! __($row) !!}</option>
@endforeach
</select><br />
<label for="date">{!! __('label.date') !!}</label> <input type="text" autocomplete="off"
id="datepicker" name="date" value="{{ format(value: $values['date'], fromFormat: FromFormat::DbDate)->date() }}" size="7" />
<br />
<label for="hours">{!! __('label.hours') !!}</label> <x-global::forms.text-input
id="hours" name="hours"
value="{{ $values['hours'] }}" size="7" /> <br />
<label for="description">{!! __('label.description') !!}</label> <x-global::forms.textarea
rows="5" cols="50" id="description" name="description">{{ $values['description'] }}</x-global::forms.textarea><br />
@if ($login::userIsAtLeast($roles::$manager))
<input style="float:left; margin-right:5px;"
type="checkbox" name="invoicedEmpl" id="invoicedEmpl"
@if (isset($values['invoicedEmpl']) && $values['invoicedEmpl'] == '1')
checked="checked"
@endif />
<label for="invoicedEmpl">{!! __('label.invoiced') !!}</label>
{!! __('label.date') !!}&nbsp;<input type="text" autocomplete="off"
id="invoicedEmplDate" name="invoicedEmplDate"
value="{{ format(value: $values['invoicedEmplDate'], fromFormat: FromFormat::DbDate)->date() }}"
size="7"/><br/>
<br/>
<input style="float:left; margin-right:5px;"
type="checkbox" name="invoicedComp" id="invoicedComp"
@if ($values['invoicedComp'] == '1')
checked="checked"
@endif />
<label for="invoicedComp">{!! __('label.invoiced_comp') !!}</label>
{!! __('label.date') !!}&nbsp;<input type="text" autocomplete="off"
id="invoicedCompDate"
name="invoicedCompDate"
value="{{ format(value: $values['invoicedCompDate'], fromFormat: FromFormat::DbDate)->date() }}"
size="7"/><br/>
<br/>
<input style="float:left; margin-right:5px;"
type="checkbox" name="paid" id="paid"
@if ($values['paid'] == '1')
checked="checked"
@endif />
<label for="paid">{!! __('label.paid') !!}</label>
{!! __('label.date') !!}&nbsp;<input type="text" autocomplete="off"
id="paidDate"
name="paidDate"
value="{{ format(value: $values['paidDate'], fromFormat: FromFormat::DbDate)->date() }}"
size="7"/><br/>
@endif
<input type="hidden" name="saveForm" value="1"/>
<p class="stdformbutton">
<x-global::forms.button tag="a" class="delete editTimeModal pull-right" link="{{ BASE_URL }}/timesheets/delTime/{{ $tpl->escape($_GET['id']) }}" state="danger" variant="outline">{!! __('links.delete') !!}</x-global::forms.button>
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="save" />
</p>
</form>

View File

@@ -0,0 +1,36 @@
@if ($login::userIsAtLeast(\Leantime\Domain\Auth\Models\Roles::$editor, true))
<li class='timerHeadMenu' id='timerHeadMenu' hx-get="{{BASE_URL}}/timesheets/stopwatch/get-status" hx-trigger="timerUpdate from:body{{ $onTheClock !== false ? ', every 60s' : '' }}" hx-swap="outerHTML">
@if ($onTheClock !== false)
<a
href='javascript:void(0);'
class='dropdown-toggle'
data-toggle='dropdown'
>{!! sprintf(
__('text.timer_on_todo'),
$onTheClock['totalTime'],
substr($onTheClock['headline'], 0, 10)
) !!}</a>
<ul class="dropdown-menu">
<li>
<a href="#/tickets/showTicket/{{ $onTheClock['id'] }}">
{!! __('links.view_todo') !!}
</a>
</li>
<li>
<a
href="javascript:void(0);"
class="punchOut"
hx-patch="{{ BASE_URL }}/hx/timesheets/stopwatch/stop-timer/"
hx-target="#timerHeadMenu"
hx-vals='{"ticketId": "{{ $onTheClock['id'] }}", "action":"stop"}'
hx-swap="outerHTML"
>{!! __('links.stop_timer') !!}</a>
</li>
</ul>
@endif
</li>
@endif

View File

@@ -0,0 +1,367 @@
@extends($layout)
@section('content')
@once
@push('scripts')
<script type="text/javascript">
function filterProjectsByClient() {
var selectedClientId = jQuery('select[name="clientId"]').val();
var projectSelect = jQuery('select[name="project"]');
if (selectedClientId === '-1') {
projectSelect.find('option[data-client-id]').show();
} else {
projectSelect.find('option[data-client-id]').hide();
projectSelect.find('option[data-client-id="' + selectedClientId + '"]').show();
}
if (projectSelect.find('option:selected').is(':hidden')) {
projectSelect.val('-1');
}
filterTicketsByProject();
}
function filterTicketsByProject() {
var selectedProjectId = jQuery('select[name="project"]').val();
var ticketSelect = jQuery('select[name="ticket"]');
if (ticketSelect.length === 0) {
return;
}
if (selectedProjectId === '-1') {
ticketSelect.find('option[data-project-id]').show();
} else {
ticketSelect.find('option[data-project-id]').hide();
ticketSelect.find('option[data-project-id="' + selectedProjectId + '"]').show();
}
if (ticketSelect.find('option:selected').is(':hidden')) {
ticketSelect.val('-1');
}
}
jQuery(document).ready(function(){
jQuery("#checkAllEmpl").change(function(){
jQuery(".invoicedEmpl").prop('checked', jQuery(this).prop("checked"));
if (jQuery(this).prop("checked") == true) {
jQuery(".invoicedEmpl").attr("checked", "checked");
jQuery(".invoicedEmpl").parent().addClass("checked");
} else {
jQuery(".invoicedEmpl").removeAttr("checked");
jQuery(".invoicedEmpl").parent().removeClass("checked");
}
});
jQuery("#checkAllComp").change(function(){
jQuery(".invoicedComp").prop('checked', jQuery(this).prop("checked"));
if (jQuery(this).prop("checked") == true) {
jQuery(".invoicedComp").attr("checked", "checked");
jQuery(".invoicedComp").parent().addClass("checked");
} else {
jQuery(".invoicedComp").removeAttr("checked");
jQuery(".invoicedComp").parent().removeClass("checked");
}
});
jQuery("#checkAllPaid").change(function(){
jQuery(".paid").prop('checked', jQuery(this).prop("checked"));
if (jQuery(this).prop("checked") == true) {
jQuery(".paid").attr("checked", "checked");
jQuery(".paid").parent().addClass("checked");
} else {
jQuery(".paid").removeAttr("checked");
jQuery(".paid").parent().removeClass("checked");
}
});
jQuery('select[name="clientId"]').change(filterProjectsByClient);
jQuery('select[name="project"]').change(filterTicketsByProject);
leantime.timesheetsController.initTimesheetsTable();
@if ($login::userIsAtLeast($roles::$manager))
leantime.timesheetsController.initEditTimeModal();
@endif
leantime.dateController.initDateRangePicker(".dateFrom", ".dateTo", 1)
});
</script>
@endpush
@endonce
<!-- page header -->
<div class="pageheader">
<div class="pageicon"><span class="fa-solid fa-business-time"></span></div>
<div class="pagetitle">
<h1>{!! __('headlines.all_timesheets') !!}</h1>
</div>
</div>
<!-- page header -->
<div class="maincontent">
<div class="maincontentinner">
<form action="{{ BASE_URL }}/timesheets/showAll" method="post" id="form" name="form">
<div class="pull-right">
<div id="tableButtons" style="display:inline-block"></div>
</div>
<div class="clearfix"></div>
<div class="headtitle" style="">
<table cellpadding="10" cellspacing="0" width="90%" class="table dataTable filterTable">
<tr>
<td>
<label for="clients">{!! __('label.client') !!}</label>
<select name="clientId">
<option value="-1">{{ strip_tags(__('menu.all_clients')) }}</option>
@foreach ($allClients as $client)
<option value="{{ $client['id'] }}"
@if ($clientFilter == $client['id'])
selected="selected"
@endif
>{{ $client['name'] }}</option>
@endforeach
</select>
</td>
<td>
<label for="projects">{!! __('label.project') !!}</label>
<select name="project" style="max-width:120px;">
<option value="-1">{{ strip_tags(__('menu.all_projects')) }}</option>
@foreach ($allProjects as $project)
<option value="{{ $project['id'] }}" data-client-id="{{ $project['clientId'] }}"
@if ($projectFilter == $project['id'])
selected="selected"
@endif
>{{ $project['name'] }}</option>
@endforeach
</select>
</td>
@if (! empty($allTickets))
<td>
<label for="ticket">{!! __('label.ticket') !!}</label>
<select name="ticket" style="max-width:120px;">
<option value="-1">{{ strip_tags(__('menu.all_tickets')) }}</option>
@foreach ($allTickets as $ticket)
<option value="{{ $ticket['id'] }}" data-project-id="{{ $ticket['projectId'] }}"
@if ($ticketFilter == $ticket['id'])
selected="selected"
@endif
>{{ $ticket['headline'] }}</option>
@endforeach
</select>
</td>
@endif
<td>
<label for="dateFrom">{!! __('label.date_from') !!}</label>
<input type="text" id="dateFrom" class="dateFrom" name="dateFrom" autocomplete="off"
value="{{ format($dateFrom)->date() }}" size="5" style="max-width:100px; margin-bottom:10px"/></td>
<td>
<label for="dateTo">{!! __('label.date_to') !!}</label>
<input type="text" id="dateTo" class="dateTo" name="dateTo" autocomplete="off"
value="{{ format($dateTo)->date() }}" size="5" style="max-width:100px; margin-bottom:10px" /></td>
<td>
<label for="userId">{!! __('label.employee') !!}</label>
<select name="userId" id="userId" onchange="submit();" style="max-width:120px;">
<option value="all">{!! __('label.all_employees') !!}</option>
@foreach ($employees as $row)
<option value="{{ $row['id'] }}"
@if ($row['id'] == $employeeFilter)
selected="selected"
@endif
>{{ sprintf(__('text.full_name'), $tpl->escape($row['firstname']), $tpl->escape($row['lastname'])) }}</option>
@endforeach
</select>
</td>
<td>
<label for="kind">{!! __('label.type') !!}</label>
<select id="kind" name="kind" onchange="submit();" style="max-width:120px;">
<option value="all">{!! __('label.all_types') !!}</option>
@foreach ($kind as $key => $row)
<option value="{{ $key }}"
@if ($key == $actKind)
selected="selected"
@endif
>{!! __($row) !!}</option>
@endforeach
</select>
</td>
<td>
<label for="invEmpl">{!! __('label.invoiced') !!}</label>
<select name="invEmpl" id="invEmpl" style="max-width:120px;">
<option value="all" @if ($invEmpl == 'all' || ! $invEmpl) selected="selected" @endif>{!! __('label.invoiced_all') !!}</option>
<option value="1" @if ($invEmpl == '1') selected="selected" @endif>{!! __('label.invoiced') !!}</option>
<option value="0" @if ($invEmpl == '0') selected="selected" @endif>{!! __('label.invoiced_not') !!}</option>
</select>
</td>
<td>
<input type="checkbox" value="on" name="invComp" id="invComp" onclick="submit();"
@if ($invComp == '1')
checked="checked"
@endif
/>
<label for="invEmpl">{!! __('label.invoiced_comp') !!}</label>
</td>
<td>
<input type="checkbox" value="on" name="paid" id="paid" onclick="submit();"
@if ($paid == '1')
checked="checked"
@endif
/>
<label for="paid">{!! __('label.paid') !!}</label>
</td>
<td>
<input type="hidden" name='filterSubmit' value="1"/>
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.search')" class="reload" />
</td>
</tr>
</table>
</div>
<table cellpadding="0" cellspacing="0" border="0" class="table table-bordered display" id="allTimesheetsTable">
<colgroup>
<col class="con0" width="100px"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1"/>
<col class="con0"/>
<col class="con1"/>
<col class="con0"/>
<col class="con1"/>
</colgroup>
<thead>
<tr>
<th>{!! __('label.id') !!}</th>
<th>{!! __('label.date') !!}</th>
<th>{!! __('label.hours') !!}</th>
<th>{!! __('label.plan_hours') !!}</th>
<th>{!! __('label.difference') !!}</th>
<th>{!! __('label.ticket') !!}</th>
<th>{!! __('label.project') !!}</th>
<th>{!! __('label.client') !!}</th>
<th>{!! __('label.employee') !!}</th>
<th>{!! __('label.type') !!}</th>
<th>{!! __('label.milestone') !!}</th>
<th>{!! __('label.tags') !!}</th>
<th>{!! __('label.description') !!}</th>
<th>{!! __('label.invoiced') !!}</th>
<th>{!! __('label.invoiced_comp') !!}</th>
<th>{!! __('label.paid') !!}</th>
</tr>
</thead>
<tbody>
@php
$sum = 0;
$billableSum = 0;
@endphp
@foreach ($allTimesheets as $row)
@php $sum = $sum + $row['hours']; @endphp
<tr>
<td data-order="{{ $row['id'] }}">
@if ($login::userIsAtLeast($roles::$manager))
<a href="{{ BASE_URL }}/timesheets/editTime/{{ $row['id'] }}" class="editTimeModal">#{{ $row['id'] . ' - ' . __('label.edit') }} </a>
@else
#{{ $row['id'] }}
@endif
</td>
<td data-order="{{ $row['workDate'] }}">
{{ format($row['workDate'])->date() }}
</td>
<td data-order="{{ $row['hours'] }}">{{ $row['hours'] }}</td>
<td data-order="{{ $row['planHours'] }}">{{ $row['planHours'] }}</td>
@php $diff = $row['planHours'] - $row['hours']; @endphp
<td data-order="{{ $diff }}">{{ $diff }}</td>
<td data-order="{{ $row['headline'] }}"><a href="#/tickets/showTicket/{{ $row['ticketId'] }}">{{ $row['headline'] }}</a></td>
<td data-order="{{ $row['name'] }}"><a href="{{ BASE_URL }}/projects/showProject/{{ $row['projectId'] }}">{{ $row['name'] }}</a></td>
<td data-order="{{ $row['clientName'] }}"><a href="{{ BASE_URL }}/clients/showClient/{{ $row['clientId'] }}">{{ $row['clientName'] }}</a></td>
<td>{!! sprintf(__('text.full_name'), $tpl->escape($row['firstname']), $tpl->escape($row['lastname'])) !!}</td>
<td>{!! __($kind[$row['kind'] ?? 'GENERAL_BILLABLE'] ?? $kind['GENERAL_BILLABLE']) !!}</td>
<td>{{ $row['milestone'] }}</td>
<td>{{ $row['tags'] }}</td>
<td>{{ $row['description'] }}</td>
<td data-order="@if ($row['invoicedEmpl'] == '1'){{ format($row['invoicedEmplDate'])->date() }}@endif">
@if ($row['invoicedEmpl'] == '1')
{{ format($row['invoicedEmplDate'])->date() }}
@else
@if ($login::userIsAtLeast($roles::$manager))
<input type="checkbox" name="invoicedEmpl[]" class="invoicedEmpl"
value="{{ $row['id'] }}" />
@endif
@endif
</td>
<td data-order="@if ($row['invoicedComp'] == '1'){{ format($row['invoicedCompDate'])->date() }}@endif">
@if ($row['invoicedComp'] == '1')
{{ format($row['invoicedCompDate'])->date() }}
@else
@if ($login::userIsAtLeast($roles::$manager))
<input type="checkbox" name="invoicedComp[]" class="invoicedComp" value="{{ $row['id'] }}" />
@endif
@endif
</td>
<td data-order="@if ($row['paid'] == '1'){{ format($row['paidDate'])->date() }}@endif">
@if ($row['paid'] == '1')
{{ format($row['paidDate'])->date() }}
@else
@if ($login::userIsAtLeast($roles::$manager))
<input type="checkbox" name="paid[]" class="paid" value="{{ $row['id'] }}" />
@endif
@endif
</td>
</tr>
@endforeach
</tbody>
<tfoot>
<tr>
<td colspan="2"><strong>{!! __('label.total_hours') !!}</strong></td>
<td colspan="10"><strong>{{ $sum }}</strong></td>
<td>
@if ($login::userIsAtLeast($roles::$manager))
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="saveInvoice" />
@endif
</td>
<td>
@if ($login::userIsAtLeast($roles::$manager))
<input type="checkbox" id="checkAllEmpl" style="vertical-align: baseline;"/> {!! __('label.select_all') !!}</td>
@endif
<td>
@if ($login::userIsAtLeast($roles::$manager))
<input type="checkbox" id="checkAllComp" style="vertical-align: baseline;"/> {!! __('label.select_all') !!}
@endif
</td>
<td>
@if ($login::userIsAtLeast($roles::$manager))
<input type="checkbox" id="checkAllPaid" style="vertical-align: baseline;"/> {!! __('label.select_all') !!}
@endif
</td>
</tr>
</tfoot>
</table>
</form>
</div>
</div>
@endsection

View File

@@ -0,0 +1,394 @@
@extends($layout)
@section('content')
@php
/** @var \Carbon\Carbon $currentDate */
@endphp
@once
@push('scripts')
<script type="text/javascript">
jQuery(document).ready(function(){
var startDate;
var endDate;
var selectCurrentWeek = function () {
window.setTimeout(function () {
jQuery('.ui-weekpicker').find('.ui-datepicker-current-day a').addClass('ui-state-active').removeClass('ui-state-default');
}, 1);
};
var setDates = function (input) {
console.log("setting dates");
var $input = jQuery(input);
var date = $input.datepicker('getDate');
if (date !== null) {
var firstDay = 1
var dayAdjustment = date.getDay() - firstDay;
if (dayAdjustment < 0) {
dayAdjustment += 7;
}
startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - dayAdjustment);
endDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - dayAdjustment + 6);
var inst = $input.data('datepicker');
var dateFormat = inst.settings.dateFormat || jQuery.datepicker._defaults.dateFormat;
jQuery('#startDate').datepicker("setDate", startDate);
jQuery('#endDate').datepicker("setDate", endDate);
jQuery('#startDate').val(jQuery.datepicker.formatDate(dateFormat, startDate, inst.settings));
jQuery('#endDate').val(jQuery.datepicker.formatDate(dateFormat, endDate, inst.settings));
}
};
jQuery('.week-picker').datepicker({
dateFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "jquery"),
dayNames: leantime.i18n.__("language.dayNames").split(","),
dayNamesMin: leantime.i18n.__("language.dayNamesMin").split(","),
dayNamesShort: leantime.i18n.__("language.dayNamesShort").split(","),
monthNames: leantime.i18n.__("language.monthNames").split(","),
monthNamesShort: leantime.i18n.__("language.monthNamesShort").split(","),
currentText: leantime.i18n.__("language.currentText"),
closeText: leantime.i18n.__("language.closeText"),
buttonText: leantime.i18n.__("language.buttonText"),
isRTL: leantime.i18n.__("language.isRTL") === "true" ? 1 : 0,
nextText: leantime.i18n.__("language.nextText"),
prevText: leantime.i18n.__("language.prevText"),
weekHeader: leantime.i18n.__("language.weekHeader"),
firstDay: 1,
autoSize: true,
navigationAsDateFormat: true,
beforeShow: function () {
jQuery('#ui-datepicker-div').addClass('ui-weekpicker');
selectCurrentWeek();
},
onClose: function () {
jQuery('#ui-datepicker-div').removeClass('ui-weekpicker');
},
showOtherMonths: true,
selectOtherMonths: true,
onSelect: function (dateText, inst) {
setDates(this);
selectCurrentWeek();
jQuery(this).change();
jQuery("#timesheetList").submit();
},
beforeShowDay: function (date) {
var cssClass = '';
if (date >= startDate && date <= endDate)
cssClass = 'ui-datepicker-current-day';
return [true, cssClass];
},
onChangeMonthYear: function (year, month, inst) {
selectCurrentWeek();
},
});
var $calendarTR = jQuery('.ui-weekpicker .ui-datepicker-calendar tr');
$calendarTR.on('mousemove', function () {
jQuery(this).find('td a').addClass('ui-state-hover');
});
$calendarTR.on('mouseleave', function () {
jQuery(this).find('td a').removeClass('ui-state-hover');
});
jQuery(".project-select").chosen();
jQuery(".ticket-select").chosen();
jQuery(".project-select").change(function(){
jQuery(".ticket-select").removeAttr("selected");
jQuery(".ticket-select").val("");
jQuery(".ticket-select").trigger("liszt:updated");
jQuery(".ticket-select option").show();
jQuery("#ticketSelect .chosen-results li").show();
var selectedValue = jQuery(this).find("option:selected").val();
jQuery(".ticket-select option").not(".project_"+selectedValue).hide();
jQuery("#ticketSelect .chosen-results li").not(".project_"+selectedValue).hide();
jQuery(".ticket-select").chosen("destroy").chosen();
});
jQuery(".ticket-select").change(function() {
var selectedValue = jQuery(this).find("option:selected").attr("data-value");
jQuery(".project-select option[value="+selectedValue+"]").attr("selected", "selected");
jQuery(".project-select").trigger("liszt:updated");
jQuery(".ticket-select").chosen("destroy").chosen();
});
jQuery("#nextWeek").click(function() {
var date = jQuery("#endDate").datepicker('getDate');
var endDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 7);
var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1);
var inst = jQuery("#endDate").data('datepicker');
var dateFormat = inst.settings.dateFormat || jQuery.datepicker._defaults.dateFormat;
jQuery('#startDate').val(jQuery.datepicker.formatDate(dateFormat, startDate, inst.settings));
jQuery('#endDate').val(jQuery.datepicker.formatDate(dateFormat, endDate, inst.settings));
jQuery("#timesheetList").submit();
});
jQuery("#prevWeek").click(function() {
var date = jQuery("#startDate").datepicker('getDate');
var endDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1);
var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7);
var inst = jQuery("#startDate").data('datepicker');
var dateFormat = inst.settings.dateFormat || jQuery.datepicker._defaults.dateFormat;
jQuery('#startDate').val(jQuery.datepicker.formatDate(dateFormat, startDate, inst.settings));
jQuery('#endDate').val(jQuery.datepicker.formatDate(dateFormat, endDate, inst.settings));
jQuery("#timesheetList").submit();
});
jQuery(".timesheetTable input").change(function(){
let colSum1 = 0; let colSum2 = 0; let colSum3 = 0; let colSum4 = 0;
let colSum5 = 0; let colSum6 = 0; let colSum7 = 0;
jQuery(".timesheetRow").each(function(i){
var rowSum = 0;
jQuery(this).find("input.hourCell").each(function(){
var currentValue = parseFloat(jQuery(this).val());
rowSum = Math.round((rowSum + currentValue)*100)/100;
var currentClass = jQuery(this).parent().attr('class');
if(currentClass.indexOf("rowday1") > -1){ colSum1 = colSum1 + currentValue; }
if(currentClass.indexOf("rowday2") > -1){ colSum2 = colSum2 + currentValue; }
if(currentClass.indexOf("rowday3") > -1){ colSum3 = colSum3 + currentValue; }
if(currentClass.indexOf("rowday4") > -1){ colSum4 = colSum4 + currentValue; }
if(currentClass.indexOf("rowday5") > -1){ colSum5 = colSum5 + currentValue; }
if(currentClass.indexOf("rowday6") > -1){ colSum6 = colSum6 + currentValue; }
if(currentClass.indexOf("rowday7") > -1){ colSum7 = colSum7 + currentValue; }
});
jQuery(this).find(".rowSum strong").text(rowSum);
});
jQuery("#day1").text(colSum1.toFixed(2)); jQuery("#day2").text(colSum2.toFixed(2));
jQuery("#day3").text(colSum3.toFixed(2)); jQuery("#day4").text(colSum4.toFixed(2));
jQuery("#day5").text(colSum5.toFixed(2)); jQuery("#day6").text(colSum6.toFixed(2));
jQuery("#day7").text(colSum7.toFixed(2));
var finalSum = colSum1 + colSum2 + colSum3 + colSum4 + colSum5 + colSum6 + colSum7;
var roundedSum = Math.round((finalSum)*100)/100;
jQuery("#finalSum").text(roundedSum);
});
});
</script>
@endpush
@endonce
<!-- page header -->
<div class="pageheader">
<div class="pageicon"><span class="fa-regular fa-clock"></span></div>
<div class="pagetitle">
<h5>{!! __('headline.overview') !!}</h5>
<h1>{!! __('headline.my_timesheets') !!}</h1>
</div>
</div>
<!-- page header -->
<div class="maincontent">
<div class="maincontentinner">
{!! $tpl->displayNotification() !!}
<form action="{{ BASE_URL }}/timesheets/showMy" method="post" id="timesheetList">
<div class="btn-group viewDropDown pull-right">
<button class="btn dropdown-toggle" data-toggle="dropdown">
{!! __('links.week_view') !!} {!! __('links.view') !!}
</button>
<ul class="dropdown-menu">
<li><a href="{{ BASE_URL }}/timesheets/showMy" class="active">{!! __('links.week_view') !!}</a></li>
<li><a href="{{ BASE_URL }}/timesheets/showMyList" >{!! __('links.list_view') !!}</a></li>
</ul>
</div>
<div class="pull-left" style="padding-left:5px; margin-top:-3px;">
<div class="padding-top-sm">
<span>{!! __('label.week_from') !!}</span>
<a href="javascript:void(0)" style="font-size:16px;" id="prevWeek"><i class="fa fa-chevron-left"></i></a>
<input type="text" class="week-picker" name="startDate" autocomplete="off" id="startDate" placeholder="{{ __('language.dateformat') }}" value="{{ $dateFrom->formatDateForUser() }}" style="margin-top:5px;"/>
{!! __('label.until') !!}
<input type="text" class="week-picker" name="endDate" autocomplete="off" id="endDate" placeholder="{{ __('language.dateformat') }}" value="{{ $dateFrom->addDays(6)->formatDateForUser() }}" style="margin-top:6px;"/>
<a href="javascript:void(0)" style="font-size:16px;" id="nextWeek"><i class="fa fa-chevron-right"></i></a>
<input type="hidden" name="search" value="1" />
</div>
</div>
<table cellpadding="0" width="100%" class="table table-bordered display timesheetTable" id="dyntableX">
<colgroup>
<col class="con0" >
<col class="con1" >
<col class="con0" >
<col class="con1" >
<col class="con0" >
<col class="con1" >
<col class="con0" >
<col class="con1" >
<col class="con0" >
<col class="con1">
<col class="con0">
</colgroup>
<thead>
@php
$days = explode(',', __('language.dayNamesShort'));
$days[] = array_shift($days);
@endphp
<tr>
<th>{!! __('label.client_product') !!}</th>
<th>{!! __('subtitles.todo') !!}</th>
<th>{!! __('label.type') !!}</th>
@php $i = 0; @endphp
@foreach ($days as $day)
<th class="@if ($dateFrom->addDays($i)->setToUserTimezone()->isToday()) active @endif">{{ $day }}<br />
{{ $dateFrom->addDays($i)->formatDateForUser() }}
@php $i++; @endphp
</th>
@endforeach
<th>{!! __('label.total') !!}</th>
</tr>
</thead>
<tbody>
@php
$colSum = [
'day1' => 0, 'day2' => 0, 'day3' => 0, 'day4' => 0,
'day5' => 0, 'day6' => 0, 'day7' => 0,
];
@endphp
@foreach ($allTimesheets as $timeRow)
@php $timesheetId = 'new'; @endphp
<tr class="gradeA timesheetRow">
<td width="14%">{{ $timeRow['clientName'] }} // {{ $timeRow['name'] }}</td>
<td width="14%">
<a href="#/tickets/showTicket/{{ $timeRow['ticketId'] }}">{{ $timeRow['headline'] }}</a>
</td>
<td width="10%">
{!! __($kind[$timeRow['kind'] ?? 'GENERAL_BILLABLE'] ?? $kind['GENERAL_BILLABLE']) !!}
@if ($timeRow['hasTimesheetOffset'])
<i class="fa-solid fa-clock-rotate-left pull-right label-blue"
data-tippy-content="This entry was likely created using a different timezone. Only existing entries can be updated in this timezone">
</i>
@endif
</td>
@foreach (array_keys($timeRow) as $dayKey)
@if (str_starts_with($dayKey, 'day'))
@php $colSum[$dayKey] = ($colSum[$dayKey] ?? 0) + $timeRow[$dayKey]['hours']; @endphp
<td width="7%" class="row{{ $dayKey }}@if ($timeRow[$dayKey]['start']->setToUserTimezone()->isToday()) active @endif">
@php
$inputNameKey = $timeRow['ticketId'] . '|' . $timeRow['kind'] . '|' . ($timeRow[$dayKey]['actualWorkDate'] ? $timeRow[$dayKey]['actualWorkDate']->formatDateForUser() : 'false') . '|' . ($timeRow[$dayKey]['actualWorkDate'] ? $timeRow[$dayKey]['actualWorkDate']->getTimestamp() : 'false');
@endphp
<input type="text"
class="hourCell"
@if (empty($timeRow[$dayKey]['actualWorkDate']))
disabled="disabled"
@endif
name="{{ $inputNameKey }}"
value="{{ $timeRow[$dayKey]['hours'] }}"
@if (empty($timeRow[$dayKey]['actualWorkDate']))
data-tippy-content="Cannot add time entry in previous timezone"
@endif
/>
@if (! empty($timeRow[$dayKey]['description']))
<i class="fa fa-circle-info" data-tippy-content="{{ $tpl->escape($timeRow[$dayKey]['description']) }}"></i>
@endif
</td>
@endif
@endforeach
<td width="7%" class="rowSum"><strong>{{ $timeRow['rowSum'] }}</strong></td>
</tr>
@endforeach
<!-- Row to add new time registration -->
<tr class="gradeA timesheetRow">
<td width="14%">
<div class="form-group" id="projectSelect">
<select data-placeholder="{{ __('input.placeholders.choose_project') }}" style="" class="project-select" >
<option value=""></option>
@foreach ($allProjects as $projectRow)
{!! sprintf(
$tpl->dispatchTplFilter(
'client_product_format',
'<option value="%s">%s / %s</option>'
),
...$tpl->dispatchTplFilter(
'client_product_values',
[
$projectRow['id'],
$tpl->escape($projectRow['clientName']),
$tpl->escape($projectRow['name']),
]
)
) !!}
@endforeach
</select>
</div>
</td>
<td width="14%">
<div class="form-group" id="ticketSelect">
<select data-placeholder="{{ __('input.placeholders.choose_todo') }}" style="" class="ticket-select" name="ticketId">
<option value=""></option>
@foreach ($allTickets as $ticketRow)
@if (in_array($ticketRow['id'], $existingTicketIds))
@continue
@endif
{!! sprintf(
$tpl->dispatchTplFilter(
'todo_format',
'<option value="%1$s" data-value="%2$s" class="project_%2$s">%1$s / %3$s</option>'
),
...$tpl->dispatchTplFilter(
'todo_values',
[
$ticketRow['id'],
$ticketRow['projectId'],
$tpl->escape($ticketRow['headline']),
]
)
) !!}
@endforeach
</select>
</div>
</td>
<td width="14%">
<select class="kind-select" name="kindId">
@foreach ($kind as $key => $kindRow)
<option value="{{ $key }}">{!! __($kindRow) !!}</option>
@endforeach
</select>
</td>
@php $i = 0; @endphp
@foreach ($days as $day)
<td width="7%" class="rowday{{ $i + 1 }}@if ($dateFrom->addDays($i)->setToUserTimezone()->isToday()) active @endif">
<input type="text" class="hourCell" name="new|GENERAL_BILLABLE|{{ $dateFrom->addDays($i)->formatDateForUser() }}|{{ $dateFrom->addDays($i)->getTimestamp() }}" value="0" />
</td>
@php $i++; @endphp
@endforeach
</tr>
</tbody>
<tfoot>
<tr style="font-weight:bold;">
<td colspan="3">{!! __('label.total') !!}</td>
@php $totalHours = 0; @endphp
@foreach ($colSum as $key => $col)
@php $totalHours += $col; @endphp
<td id="{{ $key }}">{{ $col }}</td>
@endforeach
<td id="finalSum">{{ $totalHours }}</td>
</tr>
</tfoot>
</table>
<div class="right">
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" labelText="Save" name="saveTimeSheet" class="saveTimesheetBtn" />
</div>
<div class="clearall"></div>
</form>
</div>
</div>
@endsection

View File

@@ -0,0 +1,191 @@
@extends($layout)
@section('content')
@php
use Leantime\Core\Support\FromFormat;
@endphp
<!-- page header -->
<div class="pageheader">
<div class="pageicon"><span class="fa-regular fa-clock"></span></div>
<div class="pagetitle">
<h5>{!! __('headline.overview') !!}</h5>
<h1>{!! __('headline.my_timesheets') !!}</h1>
</div>
</div>
<!-- page header -->
<div class="maincontent">
<div class="maincontentinner">
{!! $tpl->displayNotification() !!}
<form action="{{ BASE_URL }}/timesheets/showMyList" method="post" id="form" name="form">
<div class="filterWrapper tw-relative">
<a onclick="jQuery('.filterBar').toggle();" class="btn btn-default pull-left">{!! __('links.filter') !!} (1)</a>
<div class="filterBar" style="display:none; top:30px;">
<div class="filterBoxLeft">
<label for="dateFrom">{!! __('label.date_from') !!} {!! __('label.date_to') !!}</label>
<input type="text"
id="dateFrom"
class="dateFrom"
name="dateFrom"
value="{{ $dateFrom->formatDateForUser() }}"
style="margin-bottom:10px; width:90px; float:left; margin-right:10px"/>
<input type="text"
id="dateTo"
class="dateTo"
name="dateTo"
value="{{ $dateTo->formatDateForUser() }}"
style="margin-bottom:10px; width:90px" />
</div>
<div class="filterBoxLeft">
<label for="kind">{!! __('label.type') !!}</label>
<select id="kind" name="kind" onchange="submit();">
<option value="all">{!! __('label.all_types') !!}</option>
@foreach($kind as $key => $row)
<option value="{{ $key }}" @selected($key == $actKind)>{!! __($row) !!}</option>
@endforeach
</select>
</div>
<div class="filterBoxLeft">
<label>&nbsp;</label>
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.search')" class="reload" />
</div>
<div class="clearall"></div>
</div>
</div>
<div class="pull-right">
<div class="btn-group viewDropDown">
<button class="btn dropdown-toggle" data-toggle="dropdown">{!! __('links.list_view') !!} {!! __('links.view') !!}</button>
<ul class="dropdown-menu">
<li><a href="{{ BASE_URL }}/timesheets/showMy">{!! __('links.week_view') !!}</a></li>
<li><a href="{{ BASE_URL }}/timesheets/showMyList" class="active">{!! __('links.list_view') !!}</a></li>
</ul>
</div>
</div>
<div class="pull-right" style="margin-right:3px;">
<div id="tableButtons" style="display:inline-block"></div>
</div>
<div class="clearfix"></div>
<table cellpadding="0" cellspacing="0" border="0" class="table table-bordered display" id="allTimesheetsTable">
<colgroup>
<col class="con0" width="100px"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1" />
<col class="con0"/>
<col class="con1"/>
</colgroup>
<thead>
<tr>
<th>{!! __('label.id') !!}</th>
<th>{!! __('label.date') !!}</th>
<th>{!! __('label.hours') !!}</th>
<th>{!! __('label.plan_hours') !!}</th>
<th>{!! __('label.difference') !!}</th>
<th>{!! __('label.ticket') !!}</th>
<th>{!! __('label.project') !!}</th>
<th>{!! __('label.employee') !!}</th>
<th>{!! __('label.type') !!}</th>
<th>{!! __('label.description') !!}</th>
<th>{!! __('label.invoiced') !!}</th>
<th>{!! __('label.invoiced_comp') !!}</th>
<th>{!! __('label.paid') !!}</th>
</tr>
</thead>
<tbody>
@php $sum = 0; @endphp
@foreach($allTimesheets as $row)
@php $sum = $sum + $row['hours']; @endphp
<tr>
<td data-order="{{ $row['id'] }}">
<a href="{{ BASE_URL }}/timesheets/editTime/{{ $row['id'] }}" class="editTimeModal" id="editTimesheet-{{ $row['id'] }}">#{{ $row['id'] }} - {!! __('label.edit') !!} </a></td>
<td data-order="{{ format($row['workDate'])->isoDateTime() }}">
{{ format($row['workDate'])->date() }}
{{ format($row['workDate'])->time() }}
</td>
<td data-order="{{ $row['hours'] }}">
{{ $row['hours'] ?: 0 }}
</td>
<td data-order="{{ $row['planHours'] }}">
{{ $row['planHours'] ?: 0 }}
</td>
@php $diff = ($row['planHours'] ?: 0) - ($row['hours'] ?: 0); @endphp
<td data-order="{{ $diff }}">
{{ $diff }}
</td>
<td data-order="{{ $row['headline'] }}">
<a href="#/tickets/showTicket/{{ $row['ticketId'] }}">{{ $row['headline'] }}</a>
</td>
<td data-order="{{ $row['name'] }}">
<a href="{{ BASE_URL }}/projects/showProject/{{ $row['projectId'] }}">{{ $row['name'] }}</a>
</td>
<td>
{{ sprintf(__('text.full_name'), e($row['firstname']), e($row['lastname'])) }}
</td>
<td>
{!! __($kind[$row['kind']]) !!}
</td>
<td>
{{ $row['description'] }}
</td>
<td data-order="@if($row['invoicedEmpl'] == '1'){{ format(value: $row['invoicedEmplDate'], fromFormat: FromFormat::DbDate)->date() }}@endif">
@if($row['invoicedEmpl'] == '1')
{{ format(value: $row['invoicedEmplDate'], fromFormat: FromFormat::DbDate)->date() }}
@else
{!! __('label.pending') !!}
@endif
</td>
<td data-order="@if($row['invoicedComp'] == '1'){{ format(value: $row['invoicedCompDate'], fromFormat: FromFormat::DbDate)->date() }}@endif">
@if($row['invoicedComp'] == '1')
{{ format(value: $row['invoicedCompDate'], fromFormat: FromFormat::DbDate)->date() }}
@else
{!! __('label.pending') !!}
@endif
</td>
<td data-order="@if($row['paid'] == '1'){{ format(value: $row['paidDate'], fromFormat: FromFormat::DbDate)->date() }}@endif">
@if($row['paid'] == '1')
{{ format(value: $row['paidDate'], fromFormat: FromFormat::DbDate)->date() }}
@else
{!! __('label.pending') !!}
@endif
</td>
</tr>
@endforeach
</tbody>
<tfoot>
<tr>
<td></td>
<td colspan="1"><strong>{!! __('label.total_hours') !!}</strong></td>
<td colspan="11"><strong>{{ $sum }}</strong></td>
</tr>
</tfoot>
</table>
</form>
</div>
</div>
@once @push('scripts')
<script type="text/javascript">
jQuery(document).ready(function(){
leantime.timesheetsController.initTimesheetsTable();
leantime.timesheetsController.initEditTimeModal();
leantime.dateController.initDateRangePicker(".dateFrom", ".dateTo", 1);
});
</script>
@endpush @endonce
@endsection