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,76 @@
@extends($layout)
@section('content')
@php
$values = $values ?? [];
@endphp
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light">{!! __('subtitles.event') !!}</h4>
<form action="{{ BASE_URL }}/calendar/addEvent/" method="post" class='formModal'>
@csrf
@dispatchEvent('afterFormOpen')
<label for="description">{!! __('label.title') !!}</label>
<x-global::forms.text-input id="description" name="description" value="{{ $tpl->escape($values['description']) }}" /><br />
<div class="par">
<label for="dateFrom">{!! __('label.start_date') !!}</label>
<input type="text" id="event_date_from" name="dateFrom" value="" autocomplete="off" /><br/>
</div>
<div class="par">
<label for="">{!! __('label.start_time') !!}</label>
<div class="input-append bootstrap-timepicker">
<input type="time" id="event_time_from" name="timeFrom" value="" />
</div>
</div>
<div class="par">
<label for="dateTo">{!! __('label.end_date') !!}</label>
<input type="text" id="event_date_to" name="dateTo" value="" autocomplete="off" /><br/>
</div>
<div class="par">
<label for="">{!! __('label.end_time') !!} </label>
<div class="input-append bootstrap-timepicker">
<input type="time" id="event_time_to" name="timeTo" value="" />
</div>
</div>
<label for="allDay">{!! __('label.all_day') !!}</label>
<input type="checkbox" id="allDay" name="allDay"
@if (isset($values['allDay']) && $values['allDay'] === true)
checked="checked"
@endif
/><br /><br />
@dispatchEvent('beforeSubmitButton')
<p class="stdformbutton">
<input type="hidden" value="1" name="save" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="saveEvent" id="saveEvent" />
</p>
@dispatchEvent('beforeFormClose')
</form>
@once
@push('scripts')
<script type="text/javascript">
@dispatchEvent('scripts.afterOpen')
jQuery(document).ready(function() {
leantime.calendarController.initEventDatepickers();
});
@dispatchEvent('scripts.beforeClose')
</script>
@endpush
@endonce
@endsection

View File

@@ -0,0 +1,92 @@
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light"><i class="fa fa-cog"></i> {{ __('label.calendar_settings') }}</h4>
<br />
{{-- Connected Calendars Section --}}
<h5 class="subtitle">{{ __('label.connected_calendars') }}</h5>
@if(count($externalCalendars) > 0)
<ul class="simpleList" style="margin-bottom: 20px;">
@foreach($externalCalendars as $calendar)
<li style="padding: 10px; background: var(--secondary-background); border-radius: var(--box-radius-small); margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center;">
<span>
<span class="indicatorCircle" style="background-color: {{ e($calendar['colorClass']) }};"></span>
<strong>{{ $calendar['name'] }}</strong>
@if(!empty($calendar['subtitle']))
<br><small class="text-muted">{!! $calendar['subtitle'] !!}</small>
@endif
</span>
<span style="white-space: nowrap;">
@if(!empty($calendar['actions']))
{{-- Plugin-provided per-calendar actions --}}
@foreach($calendar['actions'] as $action)
<a href="{{ $action['url'] }}"
class="{{ ($action['type'] ?? 'link') === 'modal' ? 'formModal' : '' }}"
data-tippy-content="{{ $action['tooltip'] ?? '' }}">
<i class="{{ e($action['icon']) }}"></i>
</a>
&nbsp;
@endforeach
@elseif(empty($calendar['managedByPlugin']))
{{-- Default iCal calendar actions --}}
<a href="#/calendar/editExternal/{{ $calendar['id'] }}" class="formModal" data-tippy-content="{{ __('label.edit') }}">
<i class="fa fa-pen"></i>
</a>
&nbsp;
<a href="#/calendar/delExternalCalendar/{{ $calendar['id'] }}" class="delete" data-tippy-content="{{ __('label.delete') }}">
<i class="fa fa-trash"></i>
</a>
@endif
</span>
</li>
@endforeach
</ul>
@else
<p class="text-muted small" style="font-style: italic;">
{{ __('label.no_connected_calendars') }}
</p>
<br />
@endif
{{-- Plugin-injected sections (Google Calendar, etc.) --}}
{{-- Note: Plugin content via {!! !!} is trusted. Plugins are responsible for sanitizing their output. --}}
@foreach($pluginSections as $section)
<hr style="margin: 20px 0;" />
<h5 class="subtitle">
@if(isset($section['icon']))
@if(($section['iconType'] ?? 'fontawesome') === 'svg')
<span style="display: inline-block; width: 20px; height: 20px; vertical-align: middle; margin-right: 8px;">{!! $section['icon'] !!}</span>
@else
<i class="{{ e($section['icon']) }}" style="margin-right: 8px;"></i>
@endif
@endif
{{ $section['title'] }}
</h5>
@if(isset($section['description']))
<p class="text-muted small">{{ $section['description'] }}</p>
@endif
@if(isset($section['content']))
{!! $section['content'] !!}
@endif
@if(isset($section['actions']))
<div style="margin-top: 10px;">
@foreach($section['actions'] as $action)
<a href="{{ $action['url'] }}"
class="btn {{ $action['class'] ?? 'btn-default' }} {{ ($action['type'] ?? 'link') === 'modal' ? 'formModal' : '' }}">
@if(isset($action['icon']))
<i class="{{ e($action['icon']) }}"></i>
@endif
{{ $action['label'] }}
</a>
@endforeach
</div>
@endif
@endforeach
@dispatchEvent('afterCalendarSettings')

View File

@@ -0,0 +1,68 @@
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light"><i class="fa-regular fa-calendar-plus"></i> {{ __('label.connect_calendar_title') }}</h4>
<p class="subtitle">{{ __('label.connect_calendar_description') }}</p>
<br />
{{-- iCal URL Import --}}
<x-global::accordion id="connectCalendar-ical" class="noBackground">
<x-slot name="title">
<i class="fa fa-calendar-alt" style="margin-right: 5px;"></i> {{ __('label.ical_url_title') }}
</x-slot>
<x-slot name="content" style="padding-top: 10px;">
<p class="text-muted small">{{ __('label.ical_url_description') }}</p>
<form action="{{ BASE_URL }}/calendar/connectCalendar" method="post" class="formModal">
@csrf
<label for="ical_name">{{ __('label.calendar_name') }}:</label>
<x-global::forms.text-input id="ical_name" name="name" autocomplete="off" placeholder="{{ __('label.calendar_name') }}" /><br />
<label for="ical_url">{{ __('label.ical_url') }}:</label>
<x-global::forms.text-input id="ical_url" name="url" autocomplete="off" style="width:100%;" placeholder="https://example.com/calendar.ics" /><br />
<label for="ical_color">{{ __('label.color') }}:</label>
<input type="text" id="ical_color" name="colorClass" autocomplete="off" value="#082236" class="simpleColorPicker"/>
<br /><br />
<x-global::forms.button tag="input" inputType="submit" name="save" contentRole="primary" :labelText="__('label.import_ical_button')" />
</form>
</x-slot>
</x-global::accordion>
{{-- Plugin-injected providers (CalDAV, Google Calendar, etc.) --}}
{{-- Note: SVG icons via {!! !!} are trusted plugin content. Plugins are responsible for sanitizing their output. --}}
@foreach($providers as $provider)
@if($provider['id'] !== 'ical')
<x-global::accordion id="connectCalendar-{{ e($provider['id']) }}" class="noBackground">
<x-slot name="title">
@if(($provider['iconType'] ?? 'fontawesome') === 'svg')
<span style="display: inline-block; width: 18px; height: 18px; vertical-align: middle; margin-right: 5px;">{!! $provider['icon'] !!}</span>
@else
<i class="{{ e($provider['icon']) }}" style="margin-right: 5px;"></i>
@endif
{{ $provider['title'] }}
</x-slot>
<x-slot name="content" style="padding-top: 10px;">
<p class="text-muted small">{{ $provider['description'] }}</p>
<x-global::forms.button tag="a" link="{{ $provider['actionUrl'] }}"
contentRole="primary" class="{{ ($provider['actionType'] ?? 'link') === 'modal' ? 'formModal' : '' }}">
{{ $provider['actionLabel'] }}
</x-global::forms.button>
</x-slot>
</x-global::accordion>
@endif
@endforeach
@dispatchEvent('afterProviders')
<br />
<p class="text-muted small">
{{ __('label.more_integrations_hint') }}
</p>
<script type="text/javascript">
jQuery(document).ready(function() {
leantime.ticketsController.initSimpleColorPicker();
});
</script>

View File

@@ -0,0 +1,20 @@
@extends($layout)
@section('content')
@php
$id = (int) $_GET['id'];
@endphp
<h4 class="widgettitle title-light">{!! __('subtitles.delete') !!}</h4>
<form method="post" class="formModal" action="{{ BASE_URL }}/calendar/delEvent/{{ $id }}">
@dispatchEvent('afterFormOpen')
<p>{!! __('text.confirm_event_deletion') !!}</p><br />
@dispatchEvent('beforeSubmitButton')
<x-global::forms.button inputType="submit" contentRole="primary" id="saveAndClose" value="closeModal">{!! __('buttons.yes_delete') !!}</x-global::forms.button>
<x-global::forms.button tag="a" contentRole="tertiary" link="{{ BASE_URL }}/calendar/showMyCalendar">{!! __('buttons.back') !!}</x-global::forms.button>
@dispatchEvent('beforeFormClose')
</form>
@endsection

View File

@@ -0,0 +1,20 @@
@extends($layout)
@section('content')
@php
$id = (int) $_GET['id'];
@endphp
<h4 class="widgettitle title-light">{!! __('subtitles.delete') !!}</h4>
<form method="post" class="formModal" action="{{ BASE_URL }}/calendar/delExternalCalendar/{{ $id }}">
@dispatchEvent('afterFormOpen')
<p>{!! __('text.confirm_calendar_deletion') !!}</p><br />
@dispatchEvent('beforeSubmitButton')
<x-global::forms.button inputType="submit" contentRole="primary" id="saveAndClose" value="closeModal">{!! __('buttons.yes_delete') !!}</x-global::forms.button>
<x-global::forms.button tag="a" contentRole="tertiary" link="{{ BASE_URL }}/calendar/showMyCalendar">{!! __('buttons.back') !!}</x-global::forms.button>
@dispatchEvent('beforeFormClose')
</form>
@endsection

View File

@@ -0,0 +1,71 @@
@extends($layout)
@section('content')
@php
$values = $values ?? [];
@endphp
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light">{!! __('subtitles.event') !!}</h4>
<form action="{{ BASE_URL }}/calendar/editEvent/{{ $values['id'] }}" method="post" class="formModal">
@dispatchEvent('afterFormOpen')
<label for="description">{!! __('label.title') !!}</label>
<x-global::forms.text-input id="description" name="description" value="{{ $tpl->escape($values['description']) }}" /><br />
<label for="dateFrom">{!! __('label.start_date') !!}</label>
<input type="text" id="event_date_from" autocomplete="off" name="dateFrom" value="{{ format($values['dateFrom'])->date() }}" />
<div class="par">
<label> {!! __('label.start_time') !!}</label>
<div class="input-append bootstrap-timepicker">
<input type="time" id="event_time_from" name="timeFrom" value="{{ format($values['dateFrom'])->time24() }}" />
</div>
</div>
<label for="dateTo">{!! __('label.end_date') !!}</label>
<input type="text" id="event_date_to" autocomplete="off" name="dateTo" value="{{ format($values['dateTo'])->date() }}" />
<div class="par">
<label for="">{!! __('label.end_time') !!} </label>
<div class="input-append bootstrap-timepicker">
<input type="time" id="event_time_to" name="timeTo" value="{{ format($values['dateTo'])->time24() }}" />
</div>
</div>
<label for="allDay">{!! __('label.all_day') !!}</label>
<input type="checkbox" id="allDay" name="allDay"
@if ($values['allDay'] === 'true')
checked="checked"
@endif
/>
@dispatchEvent('beforeSubmitButton')
<div class="clear"></div>
<br />
<x-global::forms.button tag="a" link="{{ BASE_URL }}/calendar/delEvent/{{ (int) $_GET['id'] }}" class="formModal delete right" state="danger" variant="outline"><i class="fa fa-trash"></i> {!! __('links.delete') !!}</x-global::forms.button>
<input type="hidden" value="1" name="save" />
<x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.save')" name="saveEvent" id="save" />
<div class="clear"></div>
@dispatchEvent('beforeFormClose')
</form>
@once
@push('scripts')
<script type="text/javascript">
jQuery(document).ready(function() {
leantime.calendarController.initEventDatepickers();
});
</script>
@endpush
@endonce
@endsection

View File

@@ -0,0 +1,32 @@
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light"><i class="fa-regular fa-calendar-plus"></i> {{ __('label.edit_ical') }}</h4>
{!! __('label.import_ical_content') !!}
<form action="{{ BASE_URL }}/calendar/editExternal/{{ $values['id'] }}" method="post" class="formModal">
<input type="hidden" name="save" value="1" />
<label for="name">{{ $tpl->__('label.calendar_name') }}:</label>
<x-global::forms.text-input id="name" name="name" autocomplete="off" value="{{ $values['name'] }}" /><br />
<label for="url">{{ $tpl->__('label.ical_url') }}:</label>
<x-global::forms.text-input id="url" name="url" autocomplete="off" style="width:300px;" value="{{ $values['url'] }}" /><br />
<label for="color">{{ $tpl->__('label.color') }}:</label>
<input type="text" name="colorClass" autocomplete="off" value="{{ $values['colorClass'] }}" class="simpleColorPicker"/>
@dispatchEvent('beforeSubmitButton')
<br /><br />
<x-global::forms.button tag="input" inputType="submit" name="save" id="save" :labelText="__('buttons.save')" />
@dispatchEvent('beforeFormClose')
</form>
<script>
leantime.ticketsController.initSimpleColorPicker();
</script>

View File

@@ -0,0 +1,47 @@
@extends($layout)
@section('content')
@php
$url = $url ?? null;
@endphp
<h4 class="widgettitle title-light"><i class="fa fa-file-export"></i> {!! __('label.ical_export') !!}</h4>
{!! $tpl->displayNotification() !!}
<form class="formModal" method="post" action="{{ BASE_URL }}/calendar/export">
@dispatchEvent('afterFormOpen')
{!! __('text.ical_export_description') !!}
<br />
@if ($url)
{!! __('text.you_ical_url') !!}
<br /><x-global::forms.text-input value='{{ $url }}' style='width:100%;' />
@else
{!! __('text.no_url') !!}
@endif
<div class="row">
<div class="col-md-6">
<input type="hidden" value="1" name="generateUrl" />
@dispatchEvent('beforeSubmitButton')
<br /><x-global::forms.button tag="input" inputType="submit" contentRole="primary" :labelText="__('buttons.generate_ical_url')" />
</div>
<div class="col-md-6 align-right">
@if ($url)
<x-global::forms.button tag="a" link="{{ BASE_URL }}/calendar/export?remove=1" class="delete formModal" state="danger" variant="outline"><i class="fa fa-trash"></i> {!! __('links.remove_access') !!}</x-global::forms.button>
@endif
</div>
</div>
@dispatchEvent('beforeFormClose')
</form>
@endsection

View File

@@ -0,0 +1,31 @@
{!! $tpl->displayNotification() !!}
<h4 class="widgettitle title-light"><i class="fa-regular fa-calendar-plus"></i> {{ __('label.import_ical') }}</h4>
{!! __('label.import_ical_content') !!}
<form action="{{ BASE_URL }}/calendar/importGCal" method="post" class="formModal">
<label for="name">{{ $tpl->__('label.calendar_name') }}:</label>
<x-global::forms.text-input id="name" name="name" autocomplete="off" value="{{ $values['name'] }}" /><br />
<label for="url">{{ $tpl->__('label.ical_url') }}:</label>
<x-global::forms.text-input id="url" name="url" autocomplete="off" style="width:300px;" value="{{ $values['url'] }}" /><br />
<label for="color">{{ $tpl->__('label.color') }}:</label>
<input type="text" name="colorClass" autocomplete="off" value="{{ $values['colorClass'] }}" class="simpleColorPicker"/>
@dispatchEvent('beforeSubmitButton')
<br /><br />
<x-global::forms.button tag="input" inputType="submit" name="save" id="save" :labelText="__('buttons.save')" />
@dispatchEvent('beforeFormClose')
</form>
<script>
leantime.ticketsController.initSimpleColorPicker();
</script>

View File

@@ -0,0 +1,93 @@
@extends($layout)
@section('content')
@dispatchEvent('beforePageHeaderOpen')
<div class="pageheader">
@dispatchEvent('afterPageHeaderOpen')
<form action="{{ BASE_URL }}/index.php?act=tickets.showAll" method="post" class="searchbar">
<x-global::forms.text-input name="term" placeholder="To search type and hit enter..." />
</form>
<div class="pageicon"><span class="fa {{ $tpl->getModulePicture() }}"></span></div>
<div class="pagetitle">
<h5>{!! __('OVERVIEW') !!}</h5>
<h1>{!! __('ALL_GCCALS') !!}</h1>
</div>
@dispatchEvent('beforePageHeaderClose')
</div><!--pageheader-->
@dispatchEvent('afterPageHeaderClose')
<div class="maincontent">
<div class="maincontentinner">
<form action="">
@dispatchEvent('afterFormOpen')
<table cellpadding="0" cellspacing="0" border="0" class="allTickets table table-bordered"
id="allTickets">
<thead>
<tr>
<th>Id</th>
<th>{!! __('NAME') !!}</th>
<th>{!! __('URL') !!}</th>
<th>{!! __('COLOR') !!}</th>
</tr>
</thead>
<tbody>
@foreach ($allCalendars as $row)
<tr>
<td>{!! $tpl->displayLink('calendar.editGCal', $row['id'], ['id' => $row['id']]) !!}</td>
<td>{!! $tpl->displayLink('calendar.editGCal', $row['name'], ['id' => $row['id']]) !!}</td>
<td>{{ $row['url'] }}</td>
<td><span style="color: {{ $row['colorClass'] }}; padding:2px;">{{ $row['colorClass'] }}</span></td>
</tr>
@endforeach
</tbody>
</table>
@dispatchEvent('beforeFormClose')
</form>
@once
@push('scripts')
<script type="text/javascript">
@dispatchEvent('scripts.afterOpen')
$(document).ready(function()
{
$("#allTickets").tablesorter({
sortList:[[0,0]],
widgets: ['zebra']
}).tablesorterPager({container: $("#pager")});
//assign the sortStart event
$("#allTickets").bind("sortStart",function() {
$('#loader').show();
}).bind("sortEnd",function() {
$('#loader').hide();
});
}
);
@dispatchEvent('scripts.beforeClose')
</script>
@endpush
@endonce
<link rel='stylesheet' type='text/css' href='includes/libs/fullCalendar/fullcalendar.css' />
@endsection

View File

@@ -0,0 +1,355 @@
@extends($layout)
@section('content')
@php
if (! session()->exists('usersettings.submenuToggle.myCalendarView')) {
session(['usersettings.submenuToggle.myCalendarView' => 'dayGridMonth']);
}
@endphp
@dispatchEvent('beforePageHeaderOpen')
<div class="pageheader">
@dispatchEvent('afterPageHeaderOpen')
<div class="pageicon"><span class="fa {{ $tpl->getModulePicture() }}"></span></div>
<div class="pagetitle">
<h5>{!! __('headline.calendar') !!}</h5>
<h1>{!! __('headline.my_calendar') !!}</h1>
</div>
@dispatchEvent('beforePageHeaderClose')
</div><!--pageheader-->
@dispatchEvent('afterPageHeaderClose')
{!! $tpl->displayNotification() !!}
<div class="maincontent">
<div class="row">
<div class="col-md-2">
<div class="maincontentinner">
<h5 class="subtitle tw-pb-m">Calendars</h5>
<ul class="simpleList">
<li><span class="indicatorCircle" style="background:var(--accent1)"></span>Events</li>
<li><span class="indicatorCircle" style="background:var(--accent2)"></span>Projects & Tasks</li>
@foreach ($externalCalendars as $calendars)
<li>
@if (empty($calendars['managedByPlugin']))
<div class="inlineDropDownContainer" style="float:right;">
<a href="javascript:void(0);" class="dropdown-toggle ticketDropDown editHeadline" data-toggle="dropdown">
<i class="fa fa-ellipsis-h" aria-hidden="true"></i>
</a>
<ul class="dropdown-menu">
<li>
<a href="#/calendar/editExternal/{{ $calendars['id'] }}"><i class="fa-solid fa-pen-to-square"></i> {!! __('links.edit_calendar') !!}</a>
</li>
<li><a href="#/calendar/delExternalCalendar/{{ $calendars['id'] }}" class="delete"><i class="fa fa-trash"></i> {!! __('links.delete_external_calendar') !!}</a></li>
</ul>
</div>
@endif
<span class="indicatorCircle" style="background:{{ $calendars['colorClass'] }}"></span>{{ $calendars['name'] }}
</li>
@endforeach
</ul>
<hr />
<a href="#/calendar/connectCalendar" class="formModal" style="display:block; margin-bottom:8px; margin-left:-5px;"><i class="fa-regular fa-calendar-plus" style="width:16px;"></i> {!! __('label.connect_calendar') !!}</a>
<a href="#/calendar/calendarSettings" class="formModal" style="margin-left:-5px;"><i class="fa fa-cog" style="width:16px;"></i> {!! __('label.calendar_settings') !!}</a>
</div>
</div>
<div class="col-md-10">
<div class="maincontentinner">
<div class="row">
<div class="col-md-4">
<x-global::forms.button tag="a" link="#/calendar/addEvent" contentRole="primary" class="formModal"><i class='fa fa-plus'></i> {!! __('buttons.add_event') !!}</x-global::forms.button>
</div>
<div class="col-md-4">
<div class="fc-center center" id="calendarTitle" style="padding-top:5px;">
<h2>..</h2>
</div>
</div>
<div class="col-md-4">
<x-global::forms.button tag="a" link="#/calendar/export" contentRole="default" class="right">Export</x-global::forms.button>
<button class="fc-next-button btn btn-default right" type="button" style="margin-right:5px;">
<span class="fc-icon fc-icon-chevron-right"></span>
</button>
<button class="fc-prev-button btn btn-default right" type="button" style="margin-right:5px;">
<span class="fc-icon fc-icon-chevron-left"></span>
</button>
<button class="fc-today-button btn btn-default right" style="margin-right:5px;">today</button>
<select id="my-select" style="margin-right:5px;" class="right">
<option class="fc-timeGridDay-button fc-button fc-state-default fc-corner-right" value="timeGridDay" {{ session('usersettings.submenuToggle.myCalendarView') == 'timeGridDay' ? 'selected' : '' }}>Day</option>
<option class="fc-timeGridWeek-button fc-button fc-state-default fc-corner-right" value="timeGridWeek" {{ session('usersettings.submenuToggle.myCalendarView') == 'timeGridWeek' ? 'selected' : '' }}>Week</option>
<option class="fc-dayGridMonth-button fc-button fc-state-default fc-corner-right" value="dayGridMonth" {{ session('usersettings.submenuToggle.myCalendarView') == 'dayGridMonth' ? 'selected' : '' }}>Month</option>
<option class="fc-multiMonthYear-button fc-button fc-state-default fc-corner-right" value="multiMonthYear" {{ session('usersettings.submenuToggle.myCalendarView') == 'multiMonthYear' ? 'selected' : '' }}>Year</option>
</select>
</div>
</div>
<div id="calendar"></div>
</div>
</div>
</div>
</div>
@once
@push('scripts')
<script type='text/javascript'>
@dispatchEvent('scripts.afterOpen')
jQuery(document).ready(function() {
//leantime.calendarController.initCalendar(events);
leantime.calendarController.initExportModal();
});
var eventSources = [];
var events = {events: [
@foreach ($calendar as $calendarEvent)
{
title: {!! json_encode($calendarEvent['title']) !!},
start: new Date({{ format($calendarEvent['dateFrom'])->jsTimestamp() }}),
@if (isset($calendarEvent['dateTo']))
end: new Date({{ format($calendarEvent['dateTo'])->jsTimestamp() }}),
@endif
@if (isset($calendarEvent['allDay']) && $calendarEvent['allDay'] === true)
allDay: true,
@else
allDay: false,
@endif
enitityId: {{ $calendarEvent['id'] }},
@if (isset($calendarEvent['eventType']) && $calendarEvent['eventType'] == 'calendar')
url: '{{ CURRENT_URL }}#/calendar/editEvent/{{ $calendarEvent['id'] }}',
backgroundColor: '{{ $calendarEvent['backgroundColor'] ?? 'var(--accent2)' }}',
borderColor: '{{ $calendarEvent['borderColor'] ?? 'var(--accent2)' }}',
enitityType: "event",
dateContext: '{{ $calendarEvent['dateContext'] ?? 'plan' }}',
@else
url: '{{ CURRENT_URL }}#/tickets/showTicket/{{ $calendarEvent['id'] }}?projectId={{ $calendarEvent['projectId'] }}',
backgroundColor: '{{ $calendarEvent['backgroundColor'] ?? 'var(--accent2)' }}',
borderColor: '{{ $calendarEvent['borderColor'] ?? 'var(--accent2)' }}',
enitityType: "ticket",
dateContext: '{{ $calendarEvent['dateContext'] ?? 'edit' }}',
@endif
},
@endforeach
]};
eventSources.push(events);
@foreach ($externalCalendars as $externalCalendar)
@if (empty($externalCalendar['managedByPlugin']))
eventSources.push(
{
url: '{{ BASE_URL }}/calendar/externalCal/{{ $externalCalendar['id'] }}',
format: 'ics',
color: '{{ $externalCalendar['colorClass'] }}',
editable: false,
}
);
@endif
@endforeach
document.addEventListener('DOMContentLoaded', function() {
const heightWindow = jQuery("body").height() - 210;
const calendarEl = document.getElementById('calendar');
const calendar = new FullCalendar.Calendar(calendarEl, {
timeZone: leantime.i18n.__("usersettings.timezone"),
height: 'calc(100% - 40px)',
stickyHeaderDates: true,
initialView: '{{ session('usersettings.submenuToggle.myCalendarView') }}',
eventSources:eventSources,
editable: true,
headerToolbar: false,
dayHeaderFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "luxon"),
eventTimeFormat: leantime.dateHelper.getFormatFromSettings("timeformat", "luxon"),
slotLabelFormat: leantime.dateHelper.getFormatFromSettings("timeformat", "luxon"),
firstDay: leantime.i18n.__("language.firstDayOfWeek"),
views: {
timeGridDay: {
},
timeGridWeek: {
},
dayGridMonth: {
dayHeaderFormat: { weekday: 'short' },
},
multiMonthYear: {
showNonCurrentDates: true,
multiMonthTitleFormat: { month: 'long', year: 'numeric' },
dayHeaderFormat: { weekday: 'short' },
},
multiMonthOneMonth: {
type: 'multiMonth',
duration: {months: 1},
multiMonthTitleFormat: {month: 'long', year: 'numeric'},
dayHeaderFormat: {weekday: 'short'},
},
listWeek: {
listDayFormat: {weekday: 'long'},
listDaySideFormat: leantime.dateHelper.getFormatFromSettings("dateformat", "luxon"),
}
},
nowIndicator: true,
bootstrapFontAwesome: {
close: 'fa-times',
prev: 'fa-chevron-left',
next: 'fa-chevron-right',
prevYear: 'fa-angle-double-left',
nextYear: 'fa-angle-double-right'
},
eventDrop: function (event) {
if(event.event.extendedProps.enitityType == "ticket") {
let dataVal = {};
if(event.event.extendedProps.dateContext == "due") {
dataVal = {
id: event.event.extendedProps.enitityId,
dateToFinish: event.event.startStr
}
}else{
dataVal = {
id: event.event.extendedProps.enitityId,
editFrom: event.event.startStr,
editTo: event.event.endStr
}
}
leantime.rpc('Tickets.Tickets.patchTicket', { id: dataVal.id, values: dataVal })
.catch(function (error) {
jQuery.growl({ message: (error && error.message) ? error.message : leantime.i18n.__("short_notifications.not_saved"), style: "error" });
event.revert();
console.error('Could not update ticket dates', error);
});
}else if(event.event.extendedProps.enitityType == "event") {
leantime.rpc('Calendar.Calendar.patch', {
id: event.event.extendedProps.enitityId,
params: {
dateFrom: event.event.startStr,
dateTo: event.event.endStr
}
}).then(function (success) {
// Denied/failed update resolves to false — undo the visual move.
if (! success) { event.revert(); }
}).catch(function (error) {
console.error('Could not update event dates', error);
event.revert();
})
}
},
eventResize: function (event) {
if(event.event.extendedProps.enitityType == "ticket") {
let dataVal = {};
if(event.event.extendedProps.dateContext == "due") {
dataVal = {
id: event.event.extendedProps.enitityId,
dateToFinish: event.event.startStr
}
}else{
dataVal = {
id: event.event.extendedProps.enitityId,
editFrom: event.event.startStr,
editTo: event.event.endStr
}
}
leantime.rpc('Tickets.Tickets.patchTicket', { id: dataVal.id, values: dataVal })
.catch(function (error) {
jQuery.growl({ message: (error && error.message) ? error.message : leantime.i18n.__("short_notifications.not_saved"), style: "error" });
event.revert();
console.error('Could not update ticket dates', error);
});
}else if(event.event.extendedProps.enitityType == "event") {
leantime.rpc('Calendar.Calendar.patch', {
id: event.event.extendedProps.enitityId,
params: {
dateFrom: event.event.startStr,
dateTo: event.event.endStr
}
}).then(function (success) {
// Denied/failed update resolves to false — undo the visual move.
if (! success) { event.revert(); }
}).catch(function (error) {
console.error('Could not update event dates', error);
event.revert();
})
}
},
eventMouseEnter: function() {
},
}
);
calendar.setOption('locale', leantime.i18n.__("language.code"));
calendar.render();
calendar.scrollToTime( Date.now() );
jQuery("#calendarTitle h2").text(calendar.getCurrentData().viewTitle);
jQuery('.fc-prev-button').click(function() {
calendar.prev();
calendar.getCurrentData()
jQuery("#calendarTitle h2").text(calendar.getCurrentData().viewTitle);
});
jQuery('.fc-next-button').click(function() {
calendar.next();
jQuery("#calendarTitle h2").text(calendar.getCurrentData().viewTitle);
});
jQuery('.fc-today-button').click(function() {
calendar.today();
jQuery("#calendarTitle h2").text(calendar.getCurrentData().viewTitle);
});
jQuery("#my-select").on("change", function(e){
calendar.changeView(jQuery("#my-select option:selected").val());
leantime.rpc('Api.Api.setSubmenuState', {
submenu: "myCalendarView",
state: jQuery("#my-select option:selected").val()
}).catch(function (e) { console.error('Could not update submenu state', e); });
});
});
@dispatchEvent('scripts.beforeClose')
</script>
@endpush
@endonce
<style type="text/css">
.maincontent .maincontentinner {
height:calc(100vh - 165px);
}
</style>
@endsection