Muhammad Sulaiman Yusuf
2 years ago
8 changed files with 430 additions and 1376 deletions
@ -1,209 +1,55 @@ |
|||||||
var hrModal = $('#modal-hr > .modal-dialog > .modal-content'); |
var hrModal = $('#modal-hr > .modal-dialog > .modal-content'); |
||||||
|
|
||||||
function resetFormAssign() { |
function resetFormAssign() { |
||||||
$('#select-role-hr').val(null).trigger("change"); |
$('#select-role-hr').val(null).trigger("change"); |
||||||
$('#select-role-hr').find('option').remove(); |
$('#select-role-hr').find('option').remove(); |
||||||
$('#select-role-hr').val(""); |
$('#select-role-hr').val(""); |
||||||
$('#select-hr').val(null).trigger("change"); |
$('#select-hr').val(null).trigger("change"); |
||||||
$('#select-hr').find('option').remove(); |
$('#select-hr').find('option').remove(); |
||||||
$('#select-hr').val(""); |
$('#select-hr').val(""); |
||||||
$("#hr_role").val(""); |
$("#hr_role").val(""); |
||||||
// $("#hide-form-hr").hide();
|
$('#form-assign-hr').trigger("reset"); |
||||||
// $("#show-form-hr").show();
|
$('#btn-assign-hr').html('Assign'); |
||||||
// $("#form-assign-hr").hide();
|
$('#btn-assign-hr').prop("disabled", false); |
||||||
$('#form-assign-hr').trigger("reset"); |
|
||||||
$('#btn-assign-hr').html('Assign'); |
|
||||||
$('#btn-assign-hr').prop("disabled", false); |
|
||||||
}; |
}; |
||||||
|
|
||||||
$(document).ready(function () { |
$(document).ready(function () { |
||||||
var tableHr = $("#table-hr").DataTable({ |
var tableHr = $("#table-hr").DataTable({ |
||||||
"processing": true, |
"processing": true, |
||||||
"serverSide": true, |
"serverSide": true, |
||||||
"ajax": { |
"ajax": { |
||||||
"url": `${base_url}user-to-activity/datatables`, |
"url": `${base_url}user-to-activity/datatables`, |
||||||
"data": function (d) { |
"data": function (d) { |
||||||
d.idact = activityId; |
d.idact = activityId; |
||||||
} |
} |
||||||
}, |
}, |
||||||
"columns": [ |
"columns": [ |
||||||
{ data: 'user_name', name: 'user_name' }, |
{ data: 'user_name', name: 'user_name' }, |
||||||
{ data: 'role_name', name: 'role_name' }, |
{ data: 'role_name', name: 'role_name' }, |
||||||
{ |
] |
||||||
data: 'action', |
}); |
||||||
name: 'action', |
|
||||||
orderable: true, |
|
||||||
searchable: true |
$("#modal-hr").on("click", "#show-form-hr", function () { |
||||||
}, |
$(this).hide(); |
||||||
] |
$("#hide-form-hr").show(); |
||||||
}); |
$("#form-assign-hr").show(); |
||||||
|
}); |
||||||
|
|
||||||
|
$("#modal-hr").on("click", "#hide-form-hr", function () { |
||||||
|
$(this).hide(); |
||||||
|
resetFormAssign() |
||||||
|
$("#show-form-hr").show(); |
||||||
|
}); |
||||||
|
|
||||||
|
$('#modal-hr').on('show.bs.modal', function (event) { |
||||||
|
tableHr.draw(); |
||||||
|
}); |
||||||
|
|
||||||
|
$('#modal-hr').on('hide.bs.modal', function (event) { |
||||||
|
$("#hide-form-hr").hide(); |
||||||
|
$("#show-form-hr").show(); |
||||||
|
resetFormAssign(); |
||||||
|
}); |
||||||
|
|
||||||
function deleteHrAssign(id) { |
|
||||||
$.ajax({ |
|
||||||
url: `${base_url}user-to-activity/delete/${id}`, |
|
||||||
type: "DELETE", |
|
||||||
success: function (data) { |
|
||||||
actionHappen = true; |
|
||||||
gantt.alert("Delete Human Resource Assign Success!"); |
|
||||||
tableHr.draw(); |
|
||||||
}, |
|
||||||
error: function (data) { |
|
||||||
gantt.alert("Delete Human Resource Assign Failed, try again later!"); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
$("#modal-hr").on("click", "#show-form-hr", function () { |
|
||||||
$(this).hide(); |
|
||||||
$("#hide-form-hr").show(); |
|
||||||
$("#form-assign-hr").show(); |
|
||||||
}); |
|
||||||
|
|
||||||
$("#modal-hr").on("click", "#hide-form-hr", function () { |
|
||||||
$(this).hide(); |
|
||||||
resetFormAssign() |
|
||||||
$("#show-form-hr").show(); |
|
||||||
}); |
|
||||||
|
|
||||||
$('#modal-hr').on('show.bs.modal', function (event) { |
|
||||||
tableHr.draw(); |
|
||||||
}); |
|
||||||
|
|
||||||
$('#modal-hr').on('hide.bs.modal', function (event) { |
|
||||||
$("#hide-form-hr").hide(); |
|
||||||
$("#show-form-hr").show(); |
|
||||||
if (actionHappen) { |
|
||||||
console.log("there's action change"); |
|
||||||
updateActivity(activityId); |
|
||||||
} |
|
||||||
resetFormAssign(); |
|
||||||
}); |
|
||||||
|
|
||||||
$('#select-role-hr').select2({ |
|
||||||
dropdownParent: hrModal, |
|
||||||
placeholder: 'Pilih human resource role', |
|
||||||
allowClear: true, |
|
||||||
ajax: { |
|
||||||
url: `${base_url}project-role/select`, |
|
||||||
dataType: 'json', |
|
||||||
data: function (params) { |
|
||||||
var query = { |
|
||||||
search: params.term, |
|
||||||
type: 'public', |
|
||||||
} |
|
||||||
return query; |
|
||||||
}, |
|
||||||
processResults: function (result) { |
|
||||||
return { |
|
||||||
results: $.map(result, function (item) { |
|
||||||
// console.log("cek item", item)
|
|
||||||
return { |
|
||||||
text: item.name, |
|
||||||
id: item.id |
|
||||||
} |
|
||||||
}) |
|
||||||
}; |
|
||||||
}, |
|
||||||
cache: false |
|
||||||
} |
|
||||||
}); |
|
||||||
$('#select-hr').select2({ |
|
||||||
dropdownParent: hrModal, |
|
||||||
placeholder: 'Pilih human resource', |
|
||||||
allowClear: true, |
|
||||||
ajax: { |
|
||||||
url: `${base_url}human-resource/select`, |
|
||||||
dataType: 'json', |
|
||||||
data: function (params) { |
|
||||||
var query = { |
|
||||||
search: params.term, |
|
||||||
type: 'public', |
|
||||||
idact: activityId, |
|
||||||
idProyek: proyekId |
|
||||||
} |
|
||||||
return query; |
|
||||||
}, |
|
||||||
processResults: function (result) { |
|
||||||
return { |
|
||||||
results: $.map(result, function (item) { |
|
||||||
// console.log("cek item", item)
|
|
||||||
return { |
|
||||||
text: item.name, |
|
||||||
id: item.id, |
|
||||||
proyek_role: item.proyek_role |
|
||||||
} |
|
||||||
}) |
|
||||||
}; |
|
||||||
}, |
|
||||||
cache: false |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
$('#select-hr').on('select2:select', function (e) { |
|
||||||
console.log('select event', e.params.data); |
|
||||||
let param_data = e.params.data; |
|
||||||
if (param_data && param_data.proyek_role) { |
|
||||||
let proyek_role = param_data.proyek_role |
|
||||||
$("#hr_role").val(proyek_role); |
|
||||||
} |
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
|
|
||||||
$("#form-assign-hr").on('submit', function (e) { |
|
||||||
e.preventDefault(); |
|
||||||
|
|
||||||
$('#btn-assign-hr').html('Assign...'); |
|
||||||
$('#btn-assign-hr').prop("disabled", true); |
|
||||||
|
|
||||||
// var formData = new FormData(this);
|
|
||||||
let user_id = $("#select-hr").val(); |
|
||||||
let user_role = $("#hr_role").val(); |
|
||||||
if (!user_id || user_id < 0) { |
|
||||||
gantt.alert("Please choose user to assign!"); |
|
||||||
$('#btn-assign-hr').html('Assign'); |
|
||||||
$('#btn-assign-hr').prop("disabled", false); |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
let payload = { |
|
||||||
user_id: user_id, |
|
||||||
role_proyek_id: user_role, |
|
||||||
version_gantt_id: ganttId, |
|
||||||
proyek_id: proyekId, |
|
||||||
activity_id: activityId |
|
||||||
} |
|
||||||
$.ajax({ |
|
||||||
data: JSON.stringify(payload), |
|
||||||
url: `${base_url}user-to-activity/add`, |
|
||||||
type: "POST", |
|
||||||
processData: false, |
|
||||||
contentType: false, |
|
||||||
success: function (data) { |
|
||||||
actionHappen = true; |
|
||||||
resetFormAssign(); |
|
||||||
tableHr.draw(); |
|
||||||
gantt.alert("Human Resource Assign Success!"); |
|
||||||
}, |
|
||||||
error: function (data) { |
|
||||||
resetFormAssign(); |
|
||||||
gantt.alert("Human Resource Assign Failed, try again later!"); |
|
||||||
} |
|
||||||
}); |
|
||||||
}); |
|
||||||
|
|
||||||
$("#table-hr").on("click", ".btn-hr-delete", function () { |
|
||||||
let id = $(this).data('id'); |
|
||||||
var box = gantt.confirm({ |
|
||||||
text: "Human resource will be deleted from activity, continue?", |
|
||||||
ok: "Delete", |
|
||||||
cancel: "Cancel", |
|
||||||
callback: function (result) { |
|
||||||
if (result) { |
|
||||||
deleteHrAssign(id); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
}); |
@ -1,299 +1,66 @@ |
|||||||
var materialModal = $('#modal-material > .modal-dialog > .modal-content'); |
var materialModal = $('#modal-material > .modal-dialog > .modal-content'); |
||||||
|
|
||||||
function resetFormAssignMaterial() { |
function resetFormAssignMaterial() { |
||||||
$('#select-material').val(null).trigger("change"); |
$('#select-material').val(null).trigger("change"); |
||||||
$('#select-material').find('option').remove(); |
$('#select-material').find('option').remove(); |
||||||
$('#select-material').val(""); |
$('#select-material').val(""); |
||||||
$('#form-assign-material').trigger("reset"); |
$('#form-assign-material').trigger("reset"); |
||||||
$('#btn-assign-material').html('Assign'); |
$('#btn-assign-material').html('Assign'); |
||||||
$('#btn-assign-material').prop("disabled", false); |
$('#btn-assign-material').prop("disabled", false); |
||||||
}; |
}; |
||||||
|
|
||||||
|
|
||||||
var rupiah = document.getElementById('price-req-material'); |
|
||||||
rupiah.addEventListener('keyup', function (e) { |
|
||||||
rupiah.value = formatRibuanInput(this.value); |
|
||||||
}); |
|
||||||
|
|
||||||
var qty = document.getElementById('qty-req-material'); |
|
||||||
qty.addEventListener('keyup', function (e) { |
|
||||||
qty.value = formatRibuanInput(this.value); |
|
||||||
}); |
|
||||||
|
|
||||||
$(document).ready(function () { |
$(document).ready(function () { |
||||||
var tableMaterial = $("#table-material").DataTable({ |
var tableMaterial = $("#table-material").DataTable({ |
||||||
"processing": true, |
"processing": true, |
||||||
"serverSide": true, |
"serverSide": true, |
||||||
"ajax": { |
"ajax": { |
||||||
"url": `${base_url}assign-material/datatables`, |
"url": `${base_url}assign-material/datatables`, |
||||||
"data": function (d) { |
"data": function (d) { |
||||||
d.idact = activityId; |
d.idact = activityId; |
||||||
} |
} |
||||||
}, |
}, |
||||||
"columns": [ |
"columns": [ |
||||||
|
|
||||||
{ data: 'material_name', name: 'material_name' }, |
|
||||||
{ |
|
||||||
data: 'qty_planning', render: function (data, type) { |
|
||||||
return data ? formatRupiah(data) : '-' |
|
||||||
} |
|
||||||
}, |
|
||||||
{ data: 'uom', name: 'uom' }, |
|
||||||
{ |
|
||||||
data: 'budget', render: function (data, type) { |
|
||||||
return data ? "Rp. " + formatRupiah(data) : '-' |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
data: 'plan_date', render: function (data, type) { |
|
||||||
return data ? formatDate(data) : '-' |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
data: 'action', |
|
||||||
name: 'action', |
|
||||||
orderable: true, |
|
||||||
searchable: true |
|
||||||
}, |
|
||||||
] |
|
||||||
}); |
|
||||||
|
|
||||||
function deleteMaterialAssign(id) { |
|
||||||
$.ajax({ |
|
||||||
url: `${base_url}assign-material/delete/${id}`, |
|
||||||
type: "DELETE", |
|
||||||
success: function (data) { |
|
||||||
actionHappen = true; |
|
||||||
gantt.alert("Delete Material Assign Success!"); |
|
||||||
tableMaterial.draw(); |
|
||||||
}, |
|
||||||
error: function (data) { |
|
||||||
gantt.alert("Delete Material Assign Failed, try again later!"); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
$("#modal-material").on("click", "#show-form-material", function () { |
|
||||||
$(this).hide(); |
|
||||||
$("#hide-form-material").show(); |
|
||||||
$("#form-assign-material").show(); |
|
||||||
}); |
|
||||||
|
|
||||||
$("#modal-material").on("click", "#hide-form-material", function () { |
|
||||||
$(this).hide(); |
|
||||||
resetFormAssignMaterial() |
|
||||||
$("#show-form-material").show(); |
|
||||||
}); |
|
||||||
|
|
||||||
$('#modal-material').on('show.bs.modal', function (event) { |
|
||||||
$('#modal-material-title').html("Material Resource " + activityName); |
|
||||||
tableMaterial.draw(); |
|
||||||
}); |
|
||||||
|
|
||||||
$('#modal-material').on('hide.bs.modal', function (event) { |
|
||||||
// $("#hide-form-material").hide();
|
|
||||||
$("#show-form-material").show(); |
|
||||||
console.log("there's before action change ", actionHappen); |
|
||||||
if (actionHappen) { |
|
||||||
console.log("there's action change ", actionHappen); |
|
||||||
updateActivity(activityId); |
|
||||||
} |
|
||||||
resetFormAssignMaterial(); |
|
||||||
}); |
|
||||||
|
|
||||||
$('#select-material').select2({ |
|
||||||
dropdownParent: materialModal, |
|
||||||
placeholder: 'Pilih material resource', |
|
||||||
allowClear: true, |
|
||||||
ajax: { |
|
||||||
url: `${base_url}material-resource/select`, |
|
||||||
dataType: 'json', |
|
||||||
data: function (params) { |
|
||||||
var query = { |
|
||||||
search: params.term, |
|
||||||
type: 'public', |
|
||||||
idProyek: proyekId, |
|
||||||
idact: activityId |
|
||||||
} |
|
||||||
return query; |
|
||||||
}, |
|
||||||
processResults: function (result) { |
|
||||||
return { |
|
||||||
results: $.map(result, function (item) { |
|
||||||
// console.log("cek item", item)
|
|
||||||
return { |
|
||||||
text: item.description, |
|
||||||
id: item.id |
|
||||||
} |
|
||||||
}) |
|
||||||
}; |
|
||||||
}, |
|
||||||
cache: false |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
$('#select-material-integration').select2({ |
{ data: 'material_name', name: 'material_name' }, |
||||||
dropdownParent: materialModal, |
{ |
||||||
placeholder: 'Pilih material', |
data: 'qty_planning', render: function (data, type) { |
||||||
allowClear: true, |
return data ? formatRupiah(data) : '-' |
||||||
ajax: { |
|
||||||
url: `${adwIntegrationUrl}/request-material/get-material-integration`, |
|
||||||
type: "get", |
|
||||||
delay: 1000, |
|
||||||
data: function (params) { |
|
||||||
var query = { |
|
||||||
'name': params.term, |
|
||||||
} |
} |
||||||
return query; |
|
||||||
}, |
}, |
||||||
headers: { |
{ data: 'uom', name: 'uom' }, |
||||||
'Authorization': `Bearer ${token}` |
{ |
||||||
|
data: 'budget', render: function (data, type) { |
||||||
|
return data ? "Rp. " + formatRupiah(data) : '-' |
||||||
|
} |
||||||
}, |
}, |
||||||
processResults: function (data) { |
{ |
||||||
var dataIntegrasiMaterial = []; |
data: 'plan_date', render: function (data, type) { |
||||||
if (data.data) { |
return data ? formatDate(data) : '-' |
||||||
for(var i = 0; i < data.data.length; i++){ |
|
||||||
var newData = { |
|
||||||
id: data.data[i].description, |
|
||||||
text: data.data[i].description, |
|
||||||
} |
|
||||||
dataIntegrasiMaterial.push(newData); |
|
||||||
} |
|
||||||
} |
} |
||||||
return { |
}, |
||||||
results: dataIntegrasiMaterial |
] |
||||||
}; |
}); |
||||||
} |
|
||||||
} |
$("#modal-material").on("click", "#show-form-material", function () { |
||||||
}); |
$(this).hide(); |
||||||
|
$("#hide-form-material").show(); |
||||||
$("#form-assign-material").on('submit', function (e) { |
$("#form-assign-material").show(); |
||||||
e.preventDefault(); |
}); |
||||||
|
|
||||||
$('#btn-assign-material').html('Assign...'); |
$("#modal-material").on("click", "#hide-form-material", function () { |
||||||
$('#btn-assign-material').prop("disabled", true); |
$(this).hide(); |
||||||
|
resetFormAssignMaterial() |
||||||
// /request-material/add
|
$("#show-form-material").show(); |
||||||
let desc_req_material = $("#select-material-integration").val(); |
}); |
||||||
let required_date = $("#required-date-req-material").val(); |
|
||||||
let plan_date = $("#required-date-plan-material").val(); |
$('#modal-material').on('show.bs.modal', function (event) { |
||||||
let uom = $("#uom-req-material").val(); |
$('#modal-material-title').html("Material Resource " + activityName); |
||||||
let price = $("#price-req-material").val(); |
tableMaterial.draw(); |
||||||
let qty_planning = $("#qty-req-material").val(); |
}); |
||||||
let material_id = null; |
|
||||||
|
$('#modal-material').on('hide.bs.modal', function (event) { |
||||||
let payload = { |
$("#show-form-material").show(); |
||||||
description: desc_req_material, |
resetFormAssignMaterial(); |
||||||
fom_date: required_date, |
}); |
||||||
required_date: required_date, |
|
||||||
proyek_id: proyekId, |
|
||||||
uom: uom, |
|
||||||
qty: formatReplaceTitikRibuan(qty_planning), |
|
||||||
price: formatReplaceTitikRibuan(price) |
|
||||||
} |
|
||||||
$.ajax({ |
|
||||||
data: JSON.stringify(payload), |
|
||||||
url: `${base_url}request-material/add`, |
|
||||||
type: "POST", |
|
||||||
processData: false, |
|
||||||
contentType: false, |
|
||||||
success: function (data) { |
|
||||||
if (data && data.code === 200) { |
|
||||||
material_id = data.data.id; |
|
||||||
// actionHappen = true;
|
|
||||||
// gantt.alert("Material Request Success!");
|
|
||||||
// tableMaterial.draw();
|
|
||||||
resetFormAssignMaterial(); |
|
||||||
|
|
||||||
let payloadAssign = { |
|
||||||
proyek_id: proyekId, |
|
||||||
activity_id: activityId, |
|
||||||
material_id: material_id, |
|
||||||
qty_planning: qty_planning, |
|
||||||
plan_date: plan_date |
|
||||||
// budget: budget
|
|
||||||
} |
|
||||||
$.ajax({ |
|
||||||
data: JSON.stringify(payloadAssign), |
|
||||||
url: `${base_url}assign-material/add`, |
|
||||||
type: "POST", |
|
||||||
processData: false, |
|
||||||
contentType: false, |
|
||||||
success: function (data) { |
|
||||||
if (data && data.code === 200) { |
|
||||||
actionHappen = true; |
|
||||||
gantt.alert("Material Assign Success!"); |
|
||||||
tableMaterial.draw(); |
|
||||||
resetFormAssignMaterial(); |
|
||||||
} |
|
||||||
else { |
|
||||||
gantt.alert({ type: "error", text: data.message }); |
|
||||||
$('#btn-assign-material').html('Assign'); |
|
||||||
$('#btn-assign-material').prop("disabled", false); |
|
||||||
} |
|
||||||
}, |
|
||||||
error: function (data) { |
|
||||||
gantt.alert("Material Assign Failed, try again later!"); |
|
||||||
resetFormAssignMaterial(); |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
else { |
|
||||||
gantt.alert({ type: "error", text: data.message }); |
|
||||||
$('#btn-assign-material').html('Assign'); |
|
||||||
$('#btn-assign-material').prop("disabled", false); |
|
||||||
} |
|
||||||
}, |
|
||||||
error: function (data) { |
|
||||||
gantt.alert("Material Request Failed, try again later!"); |
|
||||||
resetFormAssignMaterial(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
// let material_id = $("#select-material").val();
|
|
||||||
|
|
||||||
// if (!material_id || material_id < 0) {
|
|
||||||
// gantt.alert("Please choose material to assign!");
|
|
||||||
// $('#btn-assign-material').html('Assign');
|
|
||||||
// $('#btn-assign-material').prop("disabled", false);
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (!qty_planning || qty_planning < 0) {
|
|
||||||
// gantt.alert("Please input qty material!");
|
|
||||||
// $('#btn-assign-material').html('Assign');
|
|
||||||
// $('#btn-assign-material').prop("disabled", false);
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if(!budget || budget < 0){
|
|
||||||
// gantt.alert("Please input price per-unit!");
|
|
||||||
// $('#btn-assign-material').html('Assign');
|
|
||||||
// $('#btn-assign-material').prop("disabled",false);
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if(material_id === null){
|
|
||||||
// gantt.alert("Material Assign Failed, try again later!");
|
|
||||||
// resetFormAssignMaterial();
|
|
||||||
// }else{
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
}); |
|
||||||
|
|
||||||
// delete from row
|
|
||||||
$("#table-material").on("click", ".btn-material-delete", function () { |
|
||||||
let id = $(this).data('id'); |
|
||||||
var box = gantt.confirm({ |
|
||||||
text: "Material resource will be deleted from activity, continue?", |
|
||||||
ok: "Delete", |
|
||||||
cancel: "Cancel", |
|
||||||
callback: function (result) { |
|
||||||
if (result) { |
|
||||||
deleteMaterialAssign(id); |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
}); |
|
||||||
}); |
}); |
||||||
|
@ -0,0 +1,284 @@ |
|||||||
|
var overlayControl = gantt.ext.overlay; |
||||||
|
var today = new Date(); |
||||||
|
|
||||||
|
function toggleOverlay() { |
||||||
|
if(overlayControl.isOverlayVisible(lineOverlay)){ |
||||||
|
gantt.config.readonly = false; |
||||||
|
overlayControl.hideOverlay(lineOverlay); |
||||||
|
gantt.$root.classList.remove("overlay_visible"); |
||||||
|
}else{ |
||||||
|
gantt.config.readonly = true; |
||||||
|
overlayControl.showOverlay(lineOverlay); |
||||||
|
gantt.$root.classList.add("overlay_visible"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function getChartScaleRange(){ |
||||||
|
var tasksRange = gantt.getSubtaskDates(); |
||||||
|
var cells = []; |
||||||
|
var scale = gantt.getScale(); |
||||||
|
if(!tasksRange.start_date){ |
||||||
|
return scale.trace_x; |
||||||
|
} |
||||||
|
|
||||||
|
scale.trace_x.forEach(function(date){ |
||||||
|
if(date >= tasksRange.start_date && date <= tasksRange.end_date){ |
||||||
|
cells.push(date); |
||||||
|
} |
||||||
|
}); |
||||||
|
return cells; |
||||||
|
} |
||||||
|
|
||||||
|
function getProgressLine(){ |
||||||
|
var tasks = gantt.getTaskByTime(); |
||||||
|
var scale = gantt.getScale(); |
||||||
|
var step = scale.unit; |
||||||
|
|
||||||
|
var timegrid = {}; |
||||||
|
|
||||||
|
var totalDuration = 0; |
||||||
|
|
||||||
|
gantt.eachTask(function(task){ |
||||||
|
if(gantt.isSummaryTask(task)){ |
||||||
|
return; |
||||||
|
} |
||||||
|
if(!task.duration){ |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
var currDate = gantt.date[scale.unit + "_start"](new Date(task.start_date)); |
||||||
|
|
||||||
|
while (currDate < task.end_date) { |
||||||
|
var date = currDate; |
||||||
|
currDate = gantt.date.add(currDate, 1, step); |
||||||
|
|
||||||
|
if (!gantt.isWorkTime({date: date, task: task, unit: step})) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
var timestamp = currDate.valueOf(); |
||||||
|
if (!timegrid[timestamp]){ |
||||||
|
timegrid[timestamp] = { |
||||||
|
planned: 0, |
||||||
|
real: 0 |
||||||
|
}; |
||||||
|
} |
||||||
|
timegrid[timestamp].planned += 1; |
||||||
|
if (date <= today){ |
||||||
|
timegrid[timestamp].real += 1 * (task.progress || 0); |
||||||
|
} |
||||||
|
totalDuration += 1; |
||||||
|
} |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
var cumulativePlannedDurations = []; |
||||||
|
var cumulativeRealDurations = []; |
||||||
|
var cumulativePredictedDurations = [] |
||||||
|
var totalPlanned = 0; |
||||||
|
var totalReal = 0; |
||||||
|
|
||||||
|
var chartScale = getChartScaleRange(); |
||||||
|
var dailyRealProgress = -1; |
||||||
|
var totalPredictedProgress = 0; |
||||||
|
for(var i = 0; i < chartScale.length; i++){ |
||||||
|
start = new Date(chartScale[i]); |
||||||
|
end = gantt.date.add(start, 1, step); |
||||||
|
var cell = timegrid[start.valueOf()] || {planned:0, real:0}; |
||||||
|
totalPlanned = cell.planned + totalPlanned; |
||||||
|
cumulativePlannedDurations.push(totalPlanned); |
||||||
|
|
||||||
|
if(start <= today) { |
||||||
|
totalReal = (cell.real||0) + totalReal; |
||||||
|
cumulativeRealDurations.push(totalReal); |
||||||
|
cumulativePredictedDurations.push(null); |
||||||
|
} else { |
||||||
|
if(dailyRealProgress < 0){ |
||||||
|
dailyRealProgress = totalReal / cumulativeRealDurations.length; |
||||||
|
totalPredictedProgress = totalReal; |
||||||
|
cumulativePredictedDurations.pop(); |
||||||
|
cumulativePredictedDurations.push(totalPredictedProgress); |
||||||
|
} |
||||||
|
totalPredictedProgress += dailyRealProgress; |
||||||
|
cumulativePredictedDurations.push(totalPredictedProgress); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for(var i = 0; i < cumulativePlannedDurations.length; i++){ |
||||||
|
cumulativePlannedDurations[i] = Math.round(cumulativePlannedDurations[i] / totalPlanned * 100); |
||||||
|
if(cumulativeRealDurations[i] !== undefined){ |
||||||
|
cumulativeRealDurations[i] = Math.round(cumulativeRealDurations[i] / totalPlanned * 100); |
||||||
|
} |
||||||
|
|
||||||
|
if(cumulativePredictedDurations[i] !== null){ |
||||||
|
cumulativePredictedDurations[i] = Math.round(cumulativePredictedDurations[i] / totalPlanned * 100); |
||||||
|
} |
||||||
|
} |
||||||
|
return {planned: cumulativePlannedDurations, real: cumulativeRealDurations, predicted: cumulativePredictedDurations}; |
||||||
|
} |
||||||
|
|
||||||
|
function getScalePaddings(){ |
||||||
|
var scale = gantt.getScale(); |
||||||
|
var dataRange = gantt.getSubtaskDates(); |
||||||
|
|
||||||
|
var chartScale = getChartScaleRange(); |
||||||
|
var newWidth = scale.col_width; |
||||||
|
var padding = { |
||||||
|
left:0, |
||||||
|
right:0 |
||||||
|
}; |
||||||
|
|
||||||
|
if(dataRange.start_date){ |
||||||
|
var yScaleLabelsWidth = 48; |
||||||
|
// fine tune values in order to align chart with the scale range
|
||||||
|
padding.left = gantt.posFromDate(dataRange.start_date) - yScaleLabelsWidth; |
||||||
|
padding.right = scale.full_width - gantt.posFromDate(dataRange.end_date) - yScaleLabelsWidth; |
||||||
|
padding.top = gantt.config.row_height - 12; |
||||||
|
padding.bottom = gantt.config.row_height - 12; |
||||||
|
} |
||||||
|
return padding; |
||||||
|
} |
||||||
|
|
||||||
|
var myChart; |
||||||
|
var lineOverlay = overlayControl.addOverlay(function(container) { |
||||||
|
|
||||||
|
var scaleLabels = []; |
||||||
|
|
||||||
|
var chartScale = getChartScaleRange(); |
||||||
|
|
||||||
|
chartScale.forEach(function(date){ |
||||||
|
scaleLabels.push(dateToStr(date)); |
||||||
|
}); |
||||||
|
|
||||||
|
var values = getProgressLine(); |
||||||
|
|
||||||
|
var canvas = document.createElement("canvas"); |
||||||
|
container.appendChild(canvas); |
||||||
|
canvas.style.height = container.offsetHeight + "px"; |
||||||
|
canvas.style.width = container.offsetWidth + "px"; |
||||||
|
|
||||||
|
var ctx = canvas.getContext("2d"); |
||||||
|
if(myChart){ |
||||||
|
myChart.destroy(); |
||||||
|
} |
||||||
|
myChart = new Chart(ctx, { |
||||||
|
type: "line", |
||||||
|
data: { |
||||||
|
datasets: [ |
||||||
|
{ |
||||||
|
label: "Planned progress", |
||||||
|
backgroundColor: "#001eff", |
||||||
|
borderColor: "#001eff", |
||||||
|
data: values.planned, |
||||||
|
fill: false, |
||||||
|
cubicInterpolationMode: 'monotone' |
||||||
|
}, |
||||||
|
{ |
||||||
|
label: "Real progress", |
||||||
|
backgroundColor: "#ff5454", |
||||||
|
borderColor: "#ff5454", |
||||||
|
data: values.real, |
||||||
|
fill: false, |
||||||
|
cubicInterpolationMode: 'monotone' |
||||||
|
} |
||||||
|
, |
||||||
|
{ |
||||||
|
label: "Real progress (predicted)", |
||||||
|
backgroundColor: "#ff5454", |
||||||
|
borderColor: "#ff5454", |
||||||
|
data: values.predicted, |
||||||
|
borderDash: [5, 10], |
||||||
|
fill: false, |
||||||
|
cubicInterpolationMode: 'monotone' |
||||||
|
} |
||||||
|
] |
||||||
|
}, |
||||||
|
options: { |
||||||
|
responsive: true, |
||||||
|
maintainAspectRatio: false, |
||||||
|
layout: { |
||||||
|
padding: getScalePaddings() |
||||||
|
}, |
||||||
|
onResize: function(chart, newSize) { |
||||||
|
var dataRange = gantt.getSubtaskDates(); |
||||||
|
if(dataRange.start_date){ |
||||||
|
// align chart with the scale range
|
||||||
|
chart.options.layout.padding = getScalePaddings(); |
||||||
|
} |
||||||
|
}, |
||||||
|
legend: { |
||||||
|
display: false |
||||||
|
}, |
||||||
|
tooltips: { |
||||||
|
mode: "index", |
||||||
|
intersect: false, |
||||||
|
callbacks: { |
||||||
|
label: function(tooltipItem, data) { |
||||||
|
var dataset = data.datasets[tooltipItem.datasetIndex]; |
||||||
|
return dataset.label + ": " + dataset.data[tooltipItem.index] + "%"; |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
hover: { |
||||||
|
mode: "nearest", |
||||||
|
intersect: true |
||||||
|
}, |
||||||
|
scales: { |
||||||
|
xAxes: [{ |
||||||
|
labels: scaleLabels, |
||||||
|
gridLines:{ |
||||||
|
display: false |
||||||
|
}, |
||||||
|
ticks: { |
||||||
|
display: false |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
position:"top", |
||||||
|
labels: scaleLabels, |
||||||
|
gridLines:{ |
||||||
|
display: false |
||||||
|
}, |
||||||
|
ticks: { |
||||||
|
display: false |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
yAxes: [{ |
||||||
|
display: true, |
||||||
|
gridLines: { |
||||||
|
display:false |
||||||
|
}, |
||||||
|
ticks: { |
||||||
|
display: true, |
||||||
|
min: 0, |
||||||
|
max: 100, |
||||||
|
stepSize: 10, |
||||||
|
callback: function(current) { |
||||||
|
if (current > 100) {return "";} |
||||||
|
return current + "%"; |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
display: true, |
||||||
|
position: "right", |
||||||
|
gridLines: { |
||||||
|
display:false |
||||||
|
}, |
||||||
|
ticks: { |
||||||
|
display: true, |
||||||
|
min: 0, |
||||||
|
max: 100, |
||||||
|
stepSize: 10, |
||||||
|
callback: function(current) { |
||||||
|
if (current > 100) {return "";} |
||||||
|
return current + "%"; |
||||||
|
} |
||||||
|
}} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
return canvas; |
||||||
|
}); |
Loading…
Reference in new issue