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,266 @@
@extends($layout)
@section('content')
@php
$todoTypeIcons = $ticketTypeIcons;
$statusLabels = $allTicketStates;
$numberofColumns = count($allTicketStates) - 1;
$size = floor(100 / $numberofColumns);
@endphp
@include('tickets::submodules.portfolioHeader')
<div class="maincontent">
@include('tickets::submodules.portfolioTabs')
<div class="maincontentinner">
{!! $tpl->displayNotification() !!}
<form action="" method="get" id="ticketSearch">
@dispatchEvent('filters.afterFormOpen')
<input type="hidden" value="1" name="search"/>
<div class="row">
<div class="col-md-5">
@dispatchEvent('filters.afterLefthandSectionOpen')
@include('tickets::submodules.ticketNewBtn')
@include('tickets::submodules.ticketFilter')
@dispatchEvent('filters.beforeLefthandSectionClose')
</div>
<div class="col-md-2 center">
@dispatchEvent('filters.afterCenterSectionOpen')
@dispatchEvent('filters.beforeCenterSectionClose')
</div>
<div class="col-md-5">
<div class="pull-right">
@dispatchEvent('filters.afterRighthandSectionOpen')
<div id="tableButtons" style="display:inline-block"></div>
@dispatchEvent('filters.beforeRighthandSectionClose')
</div>
</div>
</div>
@dispatchEvent('filters.beforeFormClose')
<div class="clearfix"></div>
</form>
@dispatchEvent('allTicketsTable.before', ['tickets' => $allTickets])
<table id="allTicketsTable" class="table table-bordered display" style="width:100%">
<colgroup>
<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" >
</colgroup>
@dispatchEvent('allTicketsTable.beforeHead', ['tickets' => $allTickets])
<thead>
@dispatchEvent('allTicketsTable.beforeHeadRow', ['tickets' => $allTickets])
<tr>
<th>{!! __('label.project_name') !!}</th>
<th>{!! __('label.title') !!}</th>
<th class="milestone-col">{!! __('label.dependent_on') !!}</th>
<th>{!! __('label.todo_status') !!}</th>
<th class="user-col">{!! __('label.owner') !!}</th>
<th>{!! __('label.planned_start_date') !!}</th>
<th>{!! __('label.planned_end_date') !!}</th>
<th>{!! __('label.planned_hours') !!}</th>
<th>{!! __('label.estimated_hours_remaining') !!}</th>
<th>{!! __('label.booked_hours') !!}</th>
<th>{!! __('label.progress') !!}</th>
<th class="no-sort"></th>
</tr>
@dispatchEvent('allTicketsTable.afterHeadRow', ['tickets' => $allTickets])
</thead>
@dispatchEvent('allTicketsTable.afterHead', ['tickets' => $allTickets])
<tbody>
@dispatchEvent('allTicketsTable.beforeFirstRow', ['tickets' => $allTickets])
@foreach ($allTickets as $rowNum => $row)
<tr>
<td><h4>{{ $row->projectName }} </h4></td>
@dispatchEvent('allTicketsTable.afterRowStart', ['rowNum' => $rowNum, 'tickets' => $allTickets])
<td data-order="{{ $row->headline }}"><a href="#/tickets/editMilestone/{{ $row->id }}">{{ $row->headline }}</a></td>
@php
if ($row->milestoneid != '' && $row->milestoneid != 0) {
$milestoneHeadline = $tpl->escape($row->milestoneHeadline);
} else {
$milestoneHeadline = __('label.no_milestone');
}
@endphp
<td class="dropdown-cell" data-order="{{ $milestoneHeadline }}">
<div class="dropdown ticketDropdown milestoneDropdown colorized show">
<a style="background-color:{{ $tpl->escape($row->milestoneColor) }}" class="dropdown-toggle label-default milestone" href="javascript:void(0);" role="button" id="milestoneDropdownMenuLink{{ $row->id }}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="text">{{ $milestoneHeadline }}</span>
&nbsp;<i class="fa fa-caret-down" aria-hidden="true"></i>
</a>
<ul class="dropdown-menu" aria-labelledby="milestoneDropdownMenuLink{{ $row->id }}">
<li class="nav-header border">{!! __('dropdown.choose_milestone') !!}</li>
<li class='dropdown-item'><a style='background-color:#b0b0b0' href='javascript:void(0);' data-label="{!! __('label.no_milestone') !!}" data-value='{{ $row->id.'_0_#b0b0b0' }}'> {!! __('label.no_milestone') !!} </a></li>
@php
foreach ($milestones as $milestone) {
if ($milestone->id != $row->id) {
echo "<li class='dropdown-item'>
<a href='javascript:void(0);' data-label='".$tpl->escape($milestone->headline)."' data-value='".$row->id.'_'.$milestone->id.'_'.$tpl->escape($milestone->tags)."' id='ticketMilestoneChange".$row->id.$milestone->id."' style='background-color:".$tpl->escape($milestone->tags)."'>".$tpl->escape($milestone->headline).'</a>';
echo '</li>';
}
}
@endphp
</ul>
</div>
</td>
@php
if (isset($statusLabels[$row->status])) {
$class = $statusLabels[$row->status]['class'];
$name = $statusLabels[$row->status]['name'];
} else {
$class = 'label-important';
$name = 'new';
}
@endphp
<td class="dropdown-cell" data-order="{{ $name }}">
<div class="dropdown ticketDropdown statusDropdown colorized show">
<a class="dropdown-toggle status {{ $class }}" href="javascript:void(0);" role="button" id="statusDropdownMenuLink{{ $row->id }}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="text">{{ $name }}</span>
&nbsp;<i class="fa fa-caret-down" aria-hidden="true"></i>
</a>
<ul class="dropdown-menu" aria-labelledby="statusDropdownMenuLink{{ $row->id }}">
<li class="nav-header border">{!! __('dropdown.choose_status') !!}</li>
@php
foreach ($statusLabels as $key => $label) {
echo "<li class='dropdown-item'>
<a href='javascript:void(0);' class='".$label['class']."' data-label='".$tpl->escape($label['name'])."' data-value='".$row->id.'_'.$key.'_'.$label['class']."' id='ticketStatusChange".$row->id.$key."' >".$tpl->escape($label['name']).'</a>';
echo '</li>';
}
@endphp
</ul>
</div>
</td>
<td class="dropdown-cell" data-order="{{ $row->editorFirstname != '' ? $tpl->escape($row->editorFirstname) : __('dropdown.not_assigned') }}">
<div class="dropdown ticketDropdown userDropdown noBg show ">
<a class="dropdown-toggle" href="javascript:void(0);" role="button" id="userDropdownMenuLink{{ $row->id }}" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="text">
@php
if ($row->editorFirstname != '') {
echo "<span id='userImage".$row->id."'><img src='".BASE_URL.'/api/users?profileImage='.$row->editorId."' width='25' style='vertical-align: middle; margin-right:5px;'/></span><span id='user".$row->id."'> ".$tpl->escape($row->editorFirstname).'</span>';
} else {
echo "<span id='userImage".$row->id."'><img src='".BASE_URL."/api/users?profileImage=false' width='25' style='vertical-align: middle; margin-right:5px;'/></span><span id='user".$row->id."'>".__('dropdown.not_assigned').'</span>';
}
@endphp
</span>
&nbsp;<i class="fa fa-caret-down" aria-hidden="true"></i>
</a>
<ul class="dropdown-menu" aria-labelledby="userDropdownMenuLink{{ $row->id }}">
<li class="nav-header border">{!! __('dropdown.choose_user') !!}</li>
@php
foreach ($users as $user) {
echo "<li class='dropdown-item'>
<a href='javascript:void(0);' data-label='".sprintf(__('text.full_name'), $tpl->escape($user['firstname']), $tpl->escape($user['lastname']))."' data-value='".$row->id.'_'.$user['id'].'_'.$user['profileId']."' id='userStatusChange".$row->id.$user['id']."' ><img src='".BASE_URL.'/api/users?profileImage='.$user['id']."' width='25' style='vertical-align: middle; margin-right:5px;'/>".sprintf(__('text.full_name'), $tpl->escape($user['firstname']), $tpl->escape($user['lastname'])).'</a>';
echo '</li>';
}
@endphp
</ul>
</div>
</td>
<td data-order="{{ $row->editFrom }}" >
{!! __('label.due_icon') !!}<input type="text" title="{{ __('label.planned_start_date') }}" value="{{ format($row->editFrom)->date() }}" class="editFromDate secretInput milestoneEditFromAsync fromDateTicket-{{ $row->id }}" data-id="{{ $row->id }}" name="editFrom" class=""/>
</td>
<td data-order="{{ $row->editTo }}" >
{!! __('label.due_icon') !!}<input type="text" title="{{ __('label.planned_end_date') }}" value="{{ format($row->editTo)->date() }}" class="editToDate secretInput milestoneEditToAsync toDateTicket-{{ $row->id }}" data-id="{{ $row->id }}" name="editTo" class="" />
</td>
<td data-order="{{ $row->planHours }}" >
{{ $row->planHours }}
</td>
<td data-order="{{ $row->hourRemaining }}" >
{{ $row->hourRemaining }}
</td>
<td data-order="{{ $row->bookedHours }}" >
{{ $row->bookedHours }}
</td>
<td data-order="{{ $row->percentDone }}">
<div class="progress " style="width: 100%;">
<div class="progress-bar progress-bar-success " role="progressbar" aria-valuenow="{{ $row->percentDone }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ $row->percentDone }}%">
<span class="sr-only">{!! sprintf(__('text.percent_complete'), $row->percentDone) !!}</span>
</div>
</div>
</td>
<td>
@if ($login::userIsAtLeast($roles::$editor))
<div class="inlineDropDownContainer">
<a href="javascript:void(0);" class="dropdown-toggle ticketDropDown" data-toggle="dropdown">
<i class="fa fa-ellipsis-v" aria-hidden="true"></i>
</a>
<ul class="dropdown-menu">
<li class="nav-header">{!! __('subtitles.todo') !!}</li>
<li><a href="#/tickets/editMilestone/{{ $row->id }}" class='ticketModal'><i class="fa fa-edit"></i> {!! __('links.edit_milestone') !!}</a></li>
<li><a href="#/tickets/moveTicket/{{ $row->id }}" class="moveTicketModal sprintModal"><i class="fa-solid fa-arrow-right-arrow-left"></i> {!! __('links.move_milestone') !!}</a></li>
<li><a href="#/tickets/delMilestone/{{ $row->id }}" class="delete"><i class="fa fa-trash"></i> {!! __('links.delete') !!}</a></li>
<li class="nav-header border"></li>
<li><a href="{{ BASE_URL }}/tickets/showAll?search=true&milestone={{ $row->id }}">{!! __('links.view_todos') !!}</a></li>
</ul>
</div>
@endif
</td>
@dispatchEvent('allTicketsTable.beforeRowEnd', ['tickets' => $allTickets, 'rowNum' => $rowNum])
</tr>
@endforeach
@dispatchEvent('allTicketsTable.afterLastRow', ['tickets' => $allTickets])
</tbody>
@dispatchEvent('allTicketsTable.afterBody', ['tickets' => $allTickets])
</table>
@dispatchEvent('allTicketsTable.afterClose', ['tickets' => $allTickets])
</div>
</div>
@once @push('scripts')
<script type="text/javascript">
@dispatchEvent('scripts.afterOpen')
jQuery(document).ready(function(){
});
leantime.ticketsController.initTicketSearchSubmit("{{ BASE_URL }}/tickets/showAll");
@if ($login::userIsAtLeast($roles::$editor))
leantime.ticketsController.initUserDropdown();
leantime.ticketsController.initMilestoneDropdown();
leantime.ticketsController.initEffortDropdown();
leantime.ticketsController.initStatusDropdown();
leantime.ticketsController.initSprintDropdown();
leantime.ticketsController.initMilestoneDatesAsyncUpdate();
@else
leantime.authController.makeInputReadonly(".maincontentinner");
@endif
leantime.ticketsController.initMilestoneTable("{{ $searchCriteria['groupBy'] }}");
@dispatchEvent('scripts.beforeClose')
</script>
@endpush @endonce
@endsection