785 lines
25 KiB
PHP
785 lines
25 KiB
PHP
@extends('layouts.app')
|
|
@section('title', __('professionalproject::lang.gantt') . ' - ' . $project->name)
|
|
|
|
@section('content')
|
|
@include('professionalproject::layouts.nav')
|
|
<section class="content-header">
|
|
<h1>@lang('professionalproject::lang.gantt'): {{ $project->name }}</h1>
|
|
</section>
|
|
<section class="content pp-gantt-page">
|
|
<div class="box box-solid pp-gantt-box">
|
|
<div class="box-header with-border pp-gantt-toolbar">
|
|
<a href="{{ action([\Modules\ProfessionalProject\Http\Controllers\ProjectController::class, 'show'], $project->id) }}" class="btn btn-default btn-sm">
|
|
<i class="fa fa-arrow-right"></i> @lang('messages.go_back')
|
|
</a>
|
|
</div>
|
|
<div class="box-body pp-gantt-body">
|
|
<div id="gantt_here"></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="modal fade pp-gantt-modal-wrap" id="pp_gantt_task_modal" tabindex="-1" role="dialog" aria-hidden="true">
|
|
<div class="modal-dialog modal-md" role="document">
|
|
<div class="modal-content pp-gantt-modal">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="@lang('messages.close')">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
<h4 class="modal-title" id="pp_gantt_modal_title"></h4>
|
|
<p class="pp-gantt-modal-dates" id="pp_gantt_modal_dates"></p>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="form-group">
|
|
<label for="pp_gantt_task_text">@lang('lang_v1.description')</label>
|
|
<textarea id="pp_gantt_task_text" class="form-control pp-gantt-textarea" rows="3" placeholder="@lang('lang_v1.description')"></textarea>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-sm-6">
|
|
<div class="form-group">
|
|
<label for="pp_gantt_start_date">@lang('business.start_date')</label>
|
|
<div class="input-group">
|
|
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
|
|
<input type="text" id="pp_gantt_start_date" class="form-control pp-gantt-datepicker" autocomplete="off" readonly>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<div class="form-group">
|
|
<label for="pp_gantt_duration">@lang('professionalproject::lang.duration_days')</label>
|
|
<div class="pp-gantt-duration-wrap">
|
|
<button type="button" class="btn btn-default pp-gantt-duration-minus" aria-label="-">
|
|
<i class="fa fa-minus"></i>
|
|
</button>
|
|
<input type="number" id="pp_gantt_duration" class="form-control pp-gantt-duration-input" min="1" step="1" value="1">
|
|
<button type="button" class="btn btn-default pp-gantt-duration-plus" aria-label="+">
|
|
<i class="fa fa-plus"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="pp-gantt-end-preview" id="pp_gantt_end_preview"></div>
|
|
</div>
|
|
<div class="modal-footer pp-gantt-modal-footer">
|
|
<button type="button" class="btn btn-danger pp-gantt-btn-delete">
|
|
<i class="fa fa-trash"></i> @lang('messages.delete')
|
|
</button>
|
|
<div class="pp-gantt-footer-actions">
|
|
<button type="button" class="btn btn-default" data-dismiss="modal">
|
|
<i class="fa fa-times"></i> @lang('messages.cancel')
|
|
</button>
|
|
<button type="button" class="btn btn-primary pp-gantt-btn-save">
|
|
<i class="fa fa-check"></i> @lang('messages.save')
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('css')
|
|
<link rel="stylesheet" href="{{ asset('modules/professionalproject/vendor/dhtmlxgantt/dhtmlxgantt.css?v=' . $asset_v) }}">
|
|
<style>
|
|
.pp-gantt-page .pp-gantt-box {
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
box-shadow: 0 2px 12px rgba(15, 23, 42, 0.08);
|
|
}
|
|
.pp-gantt-toolbar {
|
|
background: #f8fafc;
|
|
border-bottom: 1px solid #e5e7eb;
|
|
padding: 10px 15px;
|
|
}
|
|
.pp-gantt-body {
|
|
padding: 0;
|
|
background: #fff;
|
|
}
|
|
#gantt_here {
|
|
width: 100%;
|
|
height: 650px;
|
|
min-height: 500px;
|
|
background: #fff;
|
|
}
|
|
.gantt_grid_head_cell,
|
|
.gantt_scale_cell {
|
|
font-weight: 600;
|
|
color: #334155;
|
|
background: #f8fafc;
|
|
}
|
|
.gantt_grid_data .gantt_cell,
|
|
.gantt_tree_content {
|
|
color: #1e293b;
|
|
font-size: 13px;
|
|
}
|
|
.gantt_task_line {
|
|
border-radius: 4px;
|
|
border: none;
|
|
background-color: #0ea5e9;
|
|
}
|
|
.gantt_task_progress {
|
|
background-color: #0284c7;
|
|
}
|
|
.gantt_row.odd,
|
|
.gantt_task_row.odd {
|
|
background-color: #fafafa;
|
|
}
|
|
|
|
/* Hide default dhtmlx lightbox */
|
|
.gantt_cal_light,
|
|
.gantt_cal_cover {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Custom task modal */
|
|
.pp-gantt-modal-wrap .modal-dialog {
|
|
margin: 60px auto;
|
|
}
|
|
.pp-gantt-modal {
|
|
border: none;
|
|
border-radius: 12px;
|
|
overflow: hidden;
|
|
box-shadow: 0 20px 50px rgba(15, 23, 42, 0.2);
|
|
}
|
|
.pp-gantt-modal .modal-header {
|
|
background: linear-gradient(135deg, #f8fafc 0%, #eef2ff 100%);
|
|
border-bottom: 1px solid #e2e8f0;
|
|
padding: 18px 20px 14px;
|
|
}
|
|
.pp-gantt-modal .modal-header .close {
|
|
margin-top: 2px;
|
|
opacity: 0.55;
|
|
}
|
|
.pp-gantt-modal .modal-title {
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
color: #0f172a;
|
|
line-height: 1.5;
|
|
padding-left: 24px;
|
|
}
|
|
.pp-gantt-modal-dates {
|
|
margin: 8px 0 0;
|
|
font-size: 13px;
|
|
color: #64748b;
|
|
}
|
|
.pp-gantt-modal .modal-body {
|
|
padding: 20px;
|
|
}
|
|
.pp-gantt-modal .form-group label {
|
|
font-weight: 600;
|
|
color: #334155;
|
|
margin-bottom: 8px;
|
|
}
|
|
.pp-gantt-textarea {
|
|
border-radius: 8px;
|
|
border-color: #d1d5db;
|
|
resize: vertical;
|
|
min-height: 88px;
|
|
}
|
|
.pp-gantt-textarea:focus,
|
|
.pp-gantt-datepicker:focus,
|
|
.pp-gantt-duration-input:focus {
|
|
border-color: #0ea5e9;
|
|
box-shadow: 0 0 0 3px rgba(14, 165, 233, 0.15);
|
|
}
|
|
.pp-gantt-duration-wrap {
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 8px;
|
|
}
|
|
.pp-gantt-duration-wrap .btn {
|
|
width: 42px;
|
|
border-radius: 8px;
|
|
border-color: #d1d5db;
|
|
flex-shrink: 0;
|
|
}
|
|
.pp-gantt-duration-input {
|
|
text-align: center;
|
|
border-radius: 8px;
|
|
border-color: #d1d5db;
|
|
font-weight: 600;
|
|
-moz-appearance: textfield;
|
|
}
|
|
.pp-gantt-duration-input::-webkit-outer-spin-button,
|
|
.pp-gantt-duration-input::-webkit-inner-spin-button {
|
|
-webkit-appearance: none;
|
|
margin: 0;
|
|
}
|
|
.pp-gantt-end-preview {
|
|
margin-top: 4px;
|
|
padding: 12px 14px;
|
|
background: #f0f9ff;
|
|
border: 1px solid #bae6fd;
|
|
border-radius: 8px;
|
|
color: #0369a1;
|
|
font-size: 13px;
|
|
}
|
|
.pp-gantt-end-preview i {
|
|
margin-left: 6px;
|
|
}
|
|
.pp-gantt-modal-footer {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
padding: 14px 20px;
|
|
background: #f8fafc;
|
|
border-top: 1px solid #e2e8f0;
|
|
}
|
|
.pp-gantt-footer-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-right: auto;
|
|
}
|
|
.pp-gantt-modal-footer .btn {
|
|
border-radius: 8px;
|
|
min-width: 96px;
|
|
}
|
|
.pp-gantt-modal-footer .btn-primary {
|
|
background: #0ea5e9;
|
|
border-color: #0284c7;
|
|
}
|
|
.pp-gantt-modal-footer .btn-primary:hover {
|
|
background: #0284c7;
|
|
border-color: #0369a1;
|
|
}
|
|
.pp-gantt-modal-footer .btn-danger {
|
|
background: #fff;
|
|
color: #dc2626;
|
|
border-color: #fca5a5;
|
|
}
|
|
.pp-gantt-modal-footer .btn-danger:hover {
|
|
background: #fef2f2;
|
|
color: #b91c1c;
|
|
border-color: #f87171;
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('javascript')
|
|
@if(!is_persian_lang())
|
|
<script src="https://cdn.jsdelivr.net/npm/moment-jalaali@0.9.2/build/moment-jalaali.js"></script>
|
|
@endif
|
|
<script src="{{ asset('modules/professionalproject/vendor/dhtmlxgantt/dhtmlxgantt.js?v=' . $asset_v) }}"></script>
|
|
<script>
|
|
(function () {
|
|
var labels = {
|
|
save: @json(__('messages.save')),
|
|
cancel: @json(__('messages.cancel')),
|
|
delete: @json(__('messages.delete')),
|
|
description: @json(__('lang_v1.description')),
|
|
time_period: @json(__('professionalproject::lang.time_period')),
|
|
days: @json(__('professionalproject::lang.days')),
|
|
end_date: @json(__('professionalproject::lang.end_date')),
|
|
new_task: @json(__('professionalproject::lang.new_task')),
|
|
confirm_delete: @json('آیا از حذف این وظیفه مطمئن هستید؟')
|
|
};
|
|
|
|
var $modal = $('#pp_gantt_task_modal');
|
|
var modalTaskId = null;
|
|
var modalCancelled = false;
|
|
var usePersianPicker = typeof is_persian_lang !== 'undefined' && is_persian_lang;
|
|
|
|
function toPersianDigits(value) {
|
|
if (typeof persian_number === 'function') {
|
|
return persian_number(String(value));
|
|
}
|
|
return String(value);
|
|
}
|
|
|
|
function formatJalaliDate(date, includeYear) {
|
|
if (!date) {
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
if (typeof moment !== 'undefined' && typeof moment.jDate === 'function') {
|
|
var m = moment(date);
|
|
if (!m.isValid()) {
|
|
return '';
|
|
}
|
|
var fmt = includeYear ? 'jD jMMMM jYYYY' : 'jD jMMMM';
|
|
return toPersianDigits(m.format(fmt));
|
|
}
|
|
|
|
return toPersianDigits(new Intl.DateTimeFormat('fa-IR-u-ca-persian', {
|
|
numberingSystem: 'latn',
|
|
day: 'numeric',
|
|
month: 'long',
|
|
year: includeYear ? 'numeric' : undefined
|
|
}).format(date));
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function formatJalaliString(value) {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
if (value instanceof Date) {
|
|
if (typeof gantt !== 'undefined' && gantt.config && gantt.config.jalali && gantt.date) {
|
|
return formatJalaliString(gantt.date.date_to_str('%Y-%m-%d')(value));
|
|
}
|
|
return formatJalaliDate(value, true);
|
|
}
|
|
|
|
var raw = String(value).trim();
|
|
if (/^1[34]\d{2}-\d{2}-\d{2}$/.test(raw) && typeof moment !== 'undefined' && typeof moment.jDate === 'function') {
|
|
var parts = raw.split('-');
|
|
var jalaliMoment = moment.jDate(parts[0], parts[1], parts[2]);
|
|
if (jalaliMoment.isValid()) {
|
|
return toPersianDigits(jalaliMoment.format('jD jMMMM jYYYY'));
|
|
}
|
|
}
|
|
|
|
return formatJalaliDate(raw, true);
|
|
}
|
|
|
|
function toGregorianDateString(value) {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
if (value instanceof Date) {
|
|
return gantt.date.date_to_str('%Y-%m-%d')(value);
|
|
}
|
|
|
|
var raw = String(value).trim();
|
|
if (/^1[34]\d{2}-\d{2}-\d{2}$/.test(raw) && typeof moment !== 'undefined' && typeof moment.jDate === 'function') {
|
|
var parts = raw.split('-');
|
|
var jalaliMoment = moment.jDate(parts[0], parts[1], parts[2]);
|
|
if (jalaliMoment.isValid()) {
|
|
return jalaliMoment.format('YYYY-MM-DD');
|
|
}
|
|
}
|
|
|
|
return raw;
|
|
}
|
|
|
|
function normalizeDigits(value) {
|
|
if (typeof english_number === 'function') {
|
|
return english_number(String(value));
|
|
}
|
|
return String(value);
|
|
}
|
|
|
|
function momentFromPicker(value) {
|
|
if (!value || typeof moment === 'undefined') {
|
|
return null;
|
|
}
|
|
|
|
var raw = normalizeDigits(value).trim();
|
|
if (usePersianPicker && typeof moment.jDate === 'function') {
|
|
return moment(raw, 'jYYYY/jMM/jDD');
|
|
}
|
|
|
|
return moment(raw, typeof moment_date_format !== 'undefined' ? moment_date_format.toUpperCase() : 'YYYY-MM-DD');
|
|
}
|
|
|
|
function pickerValueToGanttDate(value) {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
var m = momentFromPicker(value);
|
|
if (m && m.isValid()) {
|
|
if (gantt.config.jalali && typeof moment.jDate === 'function') {
|
|
return m.format('jYYYY-jMM-jDD');
|
|
}
|
|
return m.format('YYYY-MM-DD');
|
|
}
|
|
|
|
return normalizeDigits(value).replace(/\//g, '-');
|
|
}
|
|
|
|
function ganttDateToPickerValue(value) {
|
|
if (!value) {
|
|
return '';
|
|
}
|
|
|
|
if (value instanceof Date) {
|
|
if (usePersianPicker && typeof moment.jDate === 'function') {
|
|
return moment(value).format('jYYYY/jMM/jDD');
|
|
}
|
|
return moment(value).format('YYYY-MM-DD');
|
|
}
|
|
|
|
var raw = String(value).trim();
|
|
if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
|
|
return raw.replace(/-/g, '/');
|
|
}
|
|
|
|
return raw;
|
|
}
|
|
|
|
function parseGanttDate(value) {
|
|
if (value instanceof Date) {
|
|
return value;
|
|
}
|
|
|
|
if (typeof value === 'string' && value !== '') {
|
|
return gantt.date.str_to_date(value);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function formatGanttInternalDate(date) {
|
|
if (!date) {
|
|
return '';
|
|
}
|
|
|
|
if (gantt.config.jalali && gantt.date && gantt.date.date_to_str) {
|
|
return formatJalaliString(gantt.date.date_to_str('%Y-%m-%d')(date));
|
|
}
|
|
|
|
return formatJalaliDate(date, true);
|
|
}
|
|
|
|
function formatScaleMonth(date) {
|
|
return formatGanttInternalDate(date);
|
|
}
|
|
|
|
function formatScaleDay(date) {
|
|
if (!date) {
|
|
return '';
|
|
}
|
|
|
|
if (gantt.config.jalali && gantt.date && gantt.date.date_to_str) {
|
|
var jalali = gantt.date.date_to_str('%Y-%m-%d')(date);
|
|
var parts = jalali.split('-');
|
|
if (parts.length === 3 && typeof moment !== 'undefined' && typeof moment.jDate === 'function') {
|
|
return toPersianDigits(moment.jDate(parts[0], parts[1], parts[2]).format('jMM/jDD'));
|
|
}
|
|
}
|
|
|
|
return formatJalaliDate(date, false);
|
|
}
|
|
|
|
function updateModalPreview() {
|
|
var startVal = $('#pp_gantt_start_date').val();
|
|
var duration = Math.max(1, parseInt($('#pp_gantt_duration').val(), 10) || 1);
|
|
var text = $('#pp_gantt_task_text').val().trim();
|
|
|
|
$('#pp_gantt_modal_title').text(text || labels.new_task);
|
|
|
|
if (!startVal) {
|
|
$('#pp_gantt_modal_dates').text('');
|
|
$('#pp_gantt_end_preview').html('<i class="fa fa-info-circle"></i> ' + labels.time_period);
|
|
return;
|
|
}
|
|
|
|
var ganttStart = pickerValueToGanttDate(startVal);
|
|
var startDate = parseGanttDate(ganttStart);
|
|
if (!startDate) {
|
|
return;
|
|
}
|
|
|
|
var endDate = gantt.calculateEndDate(startDate, duration);
|
|
|
|
var startLabel = formatGanttInternalDate(startDate);
|
|
var endLabel = formatGanttInternalDate(endDate);
|
|
|
|
$('#pp_gantt_modal_dates').text(startLabel + ' — ' + endLabel);
|
|
$('#pp_gantt_end_preview').html(
|
|
'<i class="fa fa-calendar"></i> <strong>' + labels.end_date + ':</strong> ' +
|
|
endLabel + ' <span class="text-muted">(' + toPersianDigits(duration) + ' ' + labels.days + ')</span>'
|
|
);
|
|
}
|
|
|
|
function initModalDatepicker() {
|
|
var $input = $('#pp_gantt_start_date');
|
|
|
|
if (usePersianPicker && typeof initPersianDatepicker === 'function') {
|
|
initPersianDatepicker('#pp_gantt_start_date', {
|
|
autoClose: true,
|
|
format: typeof datepicker_date_format !== 'undefined' ? datepicker_date_format : 'YYYY/MM/DD'
|
|
});
|
|
} else if ($.fn.datepicker) {
|
|
try {
|
|
$input.datepicker('destroy');
|
|
} catch (e) {}
|
|
$input.datepicker({
|
|
autoclose: true,
|
|
format: typeof datepicker_date_format !== 'undefined' ? datepicker_date_format : 'yyyy-mm-dd'
|
|
});
|
|
}
|
|
|
|
$input.off('change.ppGantt').on('change.ppGantt', updateModalPreview);
|
|
}
|
|
|
|
function openTaskModal(id) {
|
|
var task = gantt.getTask(id);
|
|
modalTaskId = id;
|
|
modalCancelled = true;
|
|
|
|
$('#pp_gantt_task_text').val(task.text || '');
|
|
$('#pp_gantt_duration').val(Math.max(1, parseInt(task.duration, 10) || 1));
|
|
$('#pp_gantt_start_date').val(ganttDateToPickerValue(task.start_date));
|
|
|
|
if (task.$new) {
|
|
$('.pp-gantt-btn-delete').hide();
|
|
} else {
|
|
$('.pp-gantt-btn-delete').show();
|
|
}
|
|
|
|
$modal.modal('show');
|
|
}
|
|
|
|
function saveTaskModal() {
|
|
if (!modalTaskId) {
|
|
return;
|
|
}
|
|
|
|
var text = $('#pp_gantt_task_text').val().trim();
|
|
var duration = Math.max(1, parseInt($('#pp_gantt_duration').val(), 10) || 1);
|
|
var startDate = pickerValueToGanttDate($('#pp_gantt_start_date').val());
|
|
|
|
if (!text) {
|
|
$('#pp_gantt_task_text').focus();
|
|
return;
|
|
}
|
|
|
|
if (!startDate) {
|
|
$('#pp_gantt_start_date').focus();
|
|
return;
|
|
}
|
|
|
|
modalCancelled = false;
|
|
gantt.updateTask(modalTaskId, {
|
|
text: text,
|
|
start_date: startDate,
|
|
duration: duration
|
|
});
|
|
|
|
$modal.modal('hide');
|
|
}
|
|
|
|
function deleteTaskModal() {
|
|
if (!modalTaskId || !confirm(labels.confirm_delete)) {
|
|
return;
|
|
}
|
|
|
|
modalCancelled = false;
|
|
gantt.deleteTask(modalTaskId);
|
|
$modal.modal('hide');
|
|
}
|
|
|
|
gantt.config.date_format = '%Y-%m-%d';
|
|
gantt.config.xml_date = '%Y-%m-%d';
|
|
gantt.config.order_branch = true;
|
|
gantt.config.order_branch_free = true;
|
|
gantt.config.rtl = true;
|
|
gantt.config.jalali = true;
|
|
gantt.config.grid_width = 450;
|
|
gantt.config.row_height = 36;
|
|
gantt.config.bar_height = 22;
|
|
gantt.config.fit_tasks = true;
|
|
gantt.config.scroll_on_click = false;
|
|
gantt.config.open_tree_initially = true;
|
|
gantt.config.show_errors = false;
|
|
|
|
gantt.i18n.setLocale('fa');
|
|
gantt.i18n.setLocale({
|
|
locale: 'fa',
|
|
labels: {
|
|
gantt_save_btn: labels.save,
|
|
gantt_cancel_btn: labels.cancel,
|
|
gantt_delete_btn: labels.delete,
|
|
section_description: labels.description,
|
|
section_time: labels.time_period,
|
|
column_text: @json(__('messages.name')),
|
|
column_start_date: @json(__('business.start_date')),
|
|
column_duration: @json(__('professionalproject::lang.duration_days')),
|
|
confirm_closing: '',
|
|
confirm_deleting: labels.confirm_delete,
|
|
days: labels.days
|
|
}
|
|
});
|
|
|
|
gantt.config.columns = [
|
|
{ name: 'text', label: @json(__('messages.name')), tree: true, width: 240, resize: true },
|
|
{
|
|
name: 'start_date',
|
|
label: @json(__('business.start_date')),
|
|
align: 'center',
|
|
width: 130,
|
|
resize: true,
|
|
template: function (task) {
|
|
return formatJalaliString(task.start_date);
|
|
}
|
|
},
|
|
{
|
|
name: 'duration',
|
|
label: @json(__('professionalproject::lang.duration_days')),
|
|
align: 'center',
|
|
width: 80,
|
|
resize: true,
|
|
template: function (task) {
|
|
return toPersianDigits(task.duration || 0);
|
|
}
|
|
}
|
|
];
|
|
|
|
gantt.templates.grid_date = function (date) {
|
|
return formatGanttInternalDate(date);
|
|
};
|
|
|
|
gantt.config.scale_height = 54;
|
|
gantt.config.scales = [
|
|
{
|
|
unit: 'month',
|
|
step: 1,
|
|
format: formatScaleMonth
|
|
},
|
|
{
|
|
unit: 'day',
|
|
step: 1,
|
|
format: formatScaleDay
|
|
}
|
|
];
|
|
|
|
gantt.templates.task_text = function (start, end, task) {
|
|
var text = task.text || '';
|
|
if (text.length > 36) {
|
|
return text.substring(0, 33) + '...';
|
|
}
|
|
return text;
|
|
};
|
|
|
|
gantt.templates.tooltip_text = function (start, end, task) {
|
|
return '<b>' + @json(__('messages.name')) + ':</b> ' + (task.text || '') +
|
|
'<br/><b>' + @json(__('business.start_date')) + ':</b> ' + formatGanttInternalDate(start) +
|
|
'<br/><b>' + @json(__('professionalproject::lang.end_date')) + ':</b> ' + formatGanttInternalDate(end);
|
|
};
|
|
|
|
gantt.attachEvent('onBeforeLightbox', function (id) {
|
|
openTaskModal(id);
|
|
return false;
|
|
});
|
|
|
|
$modal.on('shown.bs.modal', function () {
|
|
initModalDatepicker();
|
|
updateModalPreview();
|
|
$('#pp_gantt_task_text').focus();
|
|
});
|
|
|
|
$modal.on('hidden.bs.modal', function () {
|
|
if (modalCancelled && modalTaskId && gantt.isTaskExists(modalTaskId)) {
|
|
var task = gantt.getTask(modalTaskId);
|
|
if (task.$new) {
|
|
gantt.deleteTask(modalTaskId);
|
|
}
|
|
}
|
|
modalTaskId = null;
|
|
});
|
|
|
|
$('.pp-gantt-btn-save').on('click', saveTaskModal);
|
|
$('.pp-gantt-btn-delete').on('click', deleteTaskModal);
|
|
$modal.find('[data-dismiss="modal"]').on('click', function () {
|
|
modalCancelled = true;
|
|
});
|
|
|
|
$('.pp-gantt-duration-minus').on('click', function () {
|
|
var $input = $('#pp_gantt_duration');
|
|
var val = Math.max(1, (parseInt($input.val(), 10) || 1) - 1);
|
|
$input.val(val).trigger('change');
|
|
updateModalPreview();
|
|
});
|
|
|
|
$('.pp-gantt-duration-plus').on('click', function () {
|
|
var $input = $('#pp_gantt_duration');
|
|
var val = (parseInt($input.val(), 10) || 1) + 1;
|
|
$input.val(val).trigger('change');
|
|
updateModalPreview();
|
|
});
|
|
|
|
$('#pp_gantt_duration').on('input change', updateModalPreview);
|
|
$('#pp_gantt_task_text').on('input', updateModalPreview);
|
|
|
|
gantt.init('gantt_here');
|
|
|
|
var tasks = { data: @json($tasks), links: @json($links) };
|
|
gantt.parse(tasks);
|
|
gantt.render();
|
|
|
|
$(window).on('resize.ppGantt', function () {
|
|
gantt.render();
|
|
});
|
|
|
|
gantt.createDataProcessor({
|
|
task: {
|
|
create: function (data) {
|
|
return $.post('{{ action([\Modules\ProfessionalProject\Http\Controllers\GanttApiController::class, 'storeTask']) }}', {
|
|
_token: '{{ csrf_token() }}',
|
|
project_id: {{ $project->id }},
|
|
text: data.text,
|
|
start_date: toGregorianDateString(data.start_date),
|
|
duration: data.duration,
|
|
progress: data.progress,
|
|
parent: data.parent,
|
|
type: data.type || 'task'
|
|
});
|
|
},
|
|
update: function (data, id) {
|
|
return $.ajax({
|
|
method: 'PUT',
|
|
url: '/professional-project/gantt/task/' + id,
|
|
data: {
|
|
_token: '{{ csrf_token() }}',
|
|
text: data.text,
|
|
start_date: toGregorianDateString(data.start_date),
|
|
duration: data.duration,
|
|
progress: data.progress,
|
|
parent: data.parent,
|
|
sortorder: data.sortorder
|
|
}
|
|
});
|
|
},
|
|
delete: function (id) {
|
|
return $.ajax({
|
|
method: 'DELETE',
|
|
url: '/professional-project/gantt/task/' + id,
|
|
data: { _token: '{{ csrf_token() }}' }
|
|
});
|
|
}
|
|
},
|
|
link: {
|
|
create: function (data) {
|
|
return $.post('{{ action([\Modules\ProfessionalProject\Http\Controllers\GanttApiController::class, 'storeLink']) }}', {
|
|
_token: '{{ csrf_token() }}',
|
|
project_id: {{ $project->id }},
|
|
source: data.source,
|
|
target: data.target,
|
|
type: data.type
|
|
});
|
|
},
|
|
update: function (data, id) {
|
|
return $.ajax({
|
|
method: 'PUT',
|
|
url: '/professional-project/gantt/link/' + id,
|
|
data: {
|
|
_token: '{{ csrf_token() }}',
|
|
source: data.source,
|
|
target: data.target,
|
|
type: data.type
|
|
}
|
|
});
|
|
},
|
|
delete: function (id) {
|
|
return $.ajax({
|
|
method: 'DELETE',
|
|
url: '/professional-project/gantt/link/' + id,
|
|
data: { _token: '{{ csrf_token() }}' }
|
|
});
|
|
}
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
@endsection
|