|
|
// set work days |
|
|
|
|
|
// gantt.setWorkTime({ day:1, hours:false }); |
|
|
|
|
|
const VERSION_GANTT_EDIT_URL = `${base_url}version-gantt/edit/${ganttId}`; |
|
|
const VERSION_GANTT_UPDATE_URL = `${base_url}version-gantt/update/${ganttId}`; |
|
|
const ACTIVITY_SET_BASELINE_URL = `${base_url}project/set-baseline/${ganttId}`; |
|
|
const ACTIVITY_SET_BASELINE_ACTIVITY_URL = (id) => { |
|
|
return `${base_url}project/set-baseline-activity/${id}/${ganttId}`; |
|
|
} |
|
|
const ACTIVITY_SYNCHRONIZE_REPORT_URL = `${base_url}project/synchronize-report/${ganttId}`; |
|
|
let projectId = getUrlParameter("proyek_id"); |
|
|
var toggleTasks = "Collapse"; |
|
|
var isBaselineSet = false; |
|
|
var daysObj = [ |
|
|
{ |
|
|
text: "Sunday", |
|
|
value: "0" |
|
|
}, |
|
|
{ |
|
|
text: "Monday", |
|
|
value: "1" |
|
|
}, |
|
|
{ |
|
|
text: "Tuesday", |
|
|
value: "2" |
|
|
}, |
|
|
{ |
|
|
text: "Wednesday", |
|
|
value: "3" |
|
|
}, |
|
|
{ |
|
|
text: "Thursday", |
|
|
value: "4" |
|
|
}, |
|
|
{ |
|
|
text: "Friday", |
|
|
value: "5" |
|
|
}, |
|
|
{ |
|
|
text: "Saturday", |
|
|
value: "6" |
|
|
} |
|
|
]; |
|
|
var days = [0, 1, 2, 3, 4, 5, 6]; // Sunday -> Saturday |
|
|
|
|
|
var selectDayOffChoices = null; |
|
|
|
|
|
$(document).ready(function () { |
|
|
// init select multiple workdays |
|
|
selectDayOffChoices = new Choices('#select_dayoff', { |
|
|
removeItemButton: true, |
|
|
shouldSort: false |
|
|
// maxItemCount: 5, |
|
|
// searchResultLimit: 5, |
|
|
// renderChoiceLimit: 5 |
|
|
}); |
|
|
|
|
|
$('#gantt_setting_btn').on('click', async function () { |
|
|
const result = await axiosInstance |
|
|
.get(VERSION_GANTT_EDIT_URL, HEADER) |
|
|
.then(res => res) |
|
|
.catch((error) => error.response); |
|
|
|
|
|
if (result && result.status == 200) { |
|
|
if (result.data && result.data.data) { |
|
|
var config_dayoff = null; |
|
|
|
|
|
if (result.data.data.config_dayoff !== null) { |
|
|
config_dayoff = result.data.data.config_dayoff; |
|
|
|
|
|
if (config_dayoff && config_dayoff.length > 0) { |
|
|
var config_dayoff_arr = config_dayoff.split(','); |
|
|
for (var i = 0; i < config_dayoff_arr.length; i++) { |
|
|
var day = daysObj.find(o => parseInt(o.value) === parseInt(config_dayoff_arr[i])); |
|
|
selectDayOffChoices.setChoiceByValue(day.value); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
gantt.alert({ type: "error", text: "Failed to get settings. Please check your internet connection." }); |
|
|
} |
|
|
$('#modal_gantt_setting').modal('show'); |
|
|
}); |
|
|
|
|
|
$('#btn_save_setting').on('click', async function () { |
|
|
var holidays = []; |
|
|
var dayoff = $('#select_dayoff').val(); |
|
|
var costToComplete = $("#costToCompleteBox").val(); |
|
|
var committedCost = $("#committedCostBox").val(); |
|
|
|
|
|
dayoff = dayoff.map(item => parseInt(item)); |
|
|
var workdays = _.difference(days, dayoff); |
|
|
|
|
|
// reset the dayoff first |
|
|
for (var i = 0; i < days.length; i++) { |
|
|
gantt.unsetWorkTime({ day: days[i], hours: false }); |
|
|
} |
|
|
|
|
|
if (dayoff.length > 0) { |
|
|
for (var i = 0; i < dayoff.length; i++) { |
|
|
gantt.setWorkTime({ day: dayoff[i], hours: false }); |
|
|
} |
|
|
} |
|
|
|
|
|
let payload = { |
|
|
"config_dayoff": dayoff.join(','), |
|
|
"cost_to_complete": costToComplete ? costToComplete : 0, |
|
|
"committed_cost": committedCost ? committedCost : 0 |
|
|
} |
|
|
|
|
|
const result = await axiosInstance |
|
|
.put(VERSION_GANTT_UPDATE_URL, payload, HEADER) |
|
|
.then(res => res) |
|
|
.catch((error) => error.response); |
|
|
if (result && result.status === 200) { |
|
|
$('#modal_gantt_setting').modal('hide'); |
|
|
gantt.message("Settings updated"); |
|
|
refresData(); |
|
|
} |
|
|
else { |
|
|
gantt.alert({ type: "error", text: "Failed to update setting" }); |
|
|
} |
|
|
|
|
|
gantt.render(); |
|
|
|
|
|
}); |
|
|
$("#gantt_toggle_task_btn").on('click', function (event) { |
|
|
toggleCollapseTasks(); |
|
|
}); |
|
|
|
|
|
$("#dashboard-project").on('click', function (event) { |
|
|
window.location.href = `https://si.ospro.id/#/dashboard-project/${projectId}/${ganttId}?dashboardGantt=${true}`; |
|
|
// window.location.href = `http://localhost:3000/#/dashboard-project/${projectId}/${ganttId}?dashboardGantt=${true}`; |
|
|
}); |
|
|
|
|
|
$("#gantt-baseline").on('click', function (event) { |
|
|
setBaseline(); |
|
|
}); |
|
|
|
|
|
$("#save-activity").on('click', function (event) { |
|
|
batchUpdate(); |
|
|
}); |
|
|
|
|
|
$("#gantt-synchronize").on('click', function (event) { |
|
|
setSynchronize(); |
|
|
}); |
|
|
|
|
|
$("#compare-data").on('click', function (event) { |
|
|
compareData(ganttTask); |
|
|
}); |
|
|
|
|
|
$("#update-schedule").on('click', function (event) { |
|
|
updateSchedule(); |
|
|
}); |
|
|
|
|
|
initHolidays(); |
|
|
initGanttSettings(); |
|
|
}); |
|
|
|
|
|
async function initHolidays() { |
|
|
let payload = { |
|
|
"columns": [ |
|
|
{ "name": "version_gantt_id", "logic_operator": "=", "value": ganttId }, |
|
|
{ "name": "proyek_id", "logic_operator": "=", "value": proyekId } |
|
|
], |
|
|
"joins": [], |
|
|
"orders": { "columns": ["date"], "ascending": true }, |
|
|
"paging": { "start": 0, "length": -1 } |
|
|
} |
|
|
|
|
|
$.ajax({ |
|
|
data: JSON.stringify(payload), |
|
|
url: `${base_url}holiday/search`, |
|
|
type: "POST", |
|
|
success: function (result) { |
|
|
let dataHolidays = result.data || [] |
|
|
dataHolidays.map((val, index) => { |
|
|
var a = moment(val.date); |
|
|
var b = moment(a).add(val.duration, 'days'); |
|
|
for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) { |
|
|
let holiday = new Date(m.format('YYYY-MM-DD')); |
|
|
gantt.setWorkTime({ |
|
|
date: holiday, |
|
|
hours: false |
|
|
}); |
|
|
} |
|
|
}); |
|
|
gantt.render(); |
|
|
}, |
|
|
}); |
|
|
} |
|
|
|
|
|
async function initGanttSettings() { |
|
|
$("#scale1").attr('checked', true); |
|
|
|
|
|
// init to gantt chart view (holidays) |
|
|
const result = await axiosInstance |
|
|
.get(VERSION_GANTT_EDIT_URL, HEADER) |
|
|
.then(res => res) |
|
|
.catch((error) => error.response); |
|
|
|
|
|
if (result && result.status == 200) { |
|
|
var config_dayoff = result.data.data.config_dayoff; |
|
|
var type_gantt = result.data.data.calculation_type; |
|
|
const ganttName = result.data.data.name_version; |
|
|
|
|
|
document.getElementById("project-name-header").textContent = ganttName; |
|
|
reRenderColumns(type_gantt); |
|
|
var dayoff = []; |
|
|
if (config_dayoff && config_dayoff.length > 0) { |
|
|
dayoff = config_dayoff.split(','); |
|
|
} |
|
|
|
|
|
// reset the dayoff first |
|
|
for (var i = 0; i < days.length; i++) { |
|
|
gantt.unsetWorkTime({ day: days[i], hours: false }); |
|
|
} |
|
|
|
|
|
if (dayoff.length > 0) { |
|
|
for (var i = 0; i < dayoff.length; i++) { |
|
|
gantt.setWorkTime({ day: dayoff[i], hours: false }); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
B |
|
|
|
|
|
function expandTask() { |
|
|
gantt.eachTask(function (task) { |
|
|
task.$open = true; |
|
|
}); |
|
|
// updateProperty({task_open:true}) |
|
|
toggleTasks = "Collapse"; |
|
|
$("#gantt_toggle_task_btn").prop('title', 'Collapse Activities'); |
|
|
$("#gantt_toggle_task_btn").children().removeClass('fa-expand-alt'); |
|
|
B |
|
|
$("#gantt_toggle_task_btn").children().addClass('fa-compress-alt'); |
|
|
gantt.render(); |
|
|
} |
|
|
|
|
|
function toggleCollapseTasks() { |
|
|
// collapse task / activity |
|
|
gantt.eachTask(function (task) { |
|
|
task.$open = toggleTasks == "Expand"; |
|
|
}); |
|
|
if (toggleTasks == "Expand") { |
|
|
updateProperty({ task_open: true }) |
|
|
toggleTasks = "Collapse"; |
|
|
$("#gantt_toggle_task_btn").prop('title', 'Collapse Activities'); |
|
|
$("#gantt_toggle_task_btn").children().removeClass('fa-expand-alt'); |
|
|
$("#gantt_toggle_task_btn").children().addClass('fa-compress-alt'); // change icon to collapse |
|
|
} else { |
|
|
updateProperty({ task_open: false }) |
|
|
toggleTasks = "Expand"; |
|
|
$("#gantt_toggle_task_btn").prop('title', 'Expand Activities'); |
|
|
B |
|
|
$("#gantt_toggle_task_btn").children().removeClass('fa-compress-alt'); |
|
|
$("#gantt_toggle_task_btn").children().addClass('fa-expand-alt'); // change icon to expand |
|
|
} |
|
|
gantt.render(); |
|
|
setGanttOpen(); |
|
|
} |
|
|
|
|
|
|
|
|
// Function Show / Hide Columns |
|
|
B |
|
|
function getColumnsSelection(node) { |
|
|
var selectedColumns = node.querySelectorAll(":checked"); |
|
|
var unselectedColumn = node.querySelectorAll('input[type="checkbox"]:not(:checked)'); |
|
|
// B |
|
|
// var allSelected = node.querySelector("#check-all").prop('checked'); |
|
|
var checkedColumns = {}; |
|
|
selectedColumns.forEach(function (node) { |
|
|
checkedColumns[node.name] = true; |
|
|
}); |
|
|
unselectedColumn.forEach(function (node) { |
|
|
checkedColumns[node.name] = false; |
|
|
}); |
|
|
return checkedColumns; |
|
|
} |
|
|
|
|
|
function populateColumnsDropdown(node) { |
|
|
var visibleColumns = {}; |
|
|
// var preventHide = ['action']; |
|
|
gantt.config.columns.forEach(function (col) { |
|
|
visibleColumns[col.name] = true; |
|
|
}); |
|
|
|
|
|
var lines = []; |
|
|
allColumns.forEach(function (col) { |
|
|
var checked = visibleColumns[col.name] ? "checked" : ""; |
|
|
// skip action to be pushed |
|
|
lines.push(`<label class="${col.name === 'action' ? 'elm-hide2' : ''} dropdown-item"><input type="checkbox" name="${col.name}" ${checked}> ${col.label}</label>`); |
|
|
}); |
|
|
node.innerHTML = '<span class="dropdown-title">Show / Hide Columns</span><br>' + lines.join("<br>"); |
|
|
} |
|
|
|
|
|
function getDropdownNode() { |
|
|
return document.querySelector("#gantt_dropdown"); |
|
|
} |
|
|
|
|
|
gantt.$showDropdown = function (node) { |
|
|
var position = node.getBoundingClientRect(); |
|
|
var dropDown = getDropdownNode(); |
|
|
dropDown.style.top = position.bottom + "px"; |
|
|
dropDown.style.left = position.left - 150 + "px"; |
|
|
dropDown.style.display = "block"; |
|
|
populateColumnsDropdown(dropDown); |
|
|
|
|
|
dropDown.onchange = function () { |
|
|
var selection = getColumnsSelection(dropDown); |
|
|
if (readOnly && parseInt(readOnly) == 0) { |
|
|
updateShowHideColumn(selection) |
|
|
} |
|
|
gantt.config.columns = createColumnsConfig(selection); |
|
|
gantt.render(); |
|
|
} |
|
|
|
|
|
dropDown.keep = true; |
|
|
setTimeout(function () { |
|
|
dropDown.keep = false; |
|
|
}) |
|
|
} |
|
|
|
|
|
gantt.$hideDropdown = function () { |
|
|
var dropDown = getDropdownNode(); |
|
|
dropDown.style.display = "none"; |
|
|
} |
|
|
|
|
|
window.addEventListener("click", function (event) { |
|
|
if (!event.target.closest("#gantt_dropdown") && !getDropdownNode().keep) { |
|
|
gantt.$hideDropdown(); |
|
|
} |
|
|
}); |
|
|
|
|
|
// End Function Show / Hide Columns |
|
|
|
|
|
|
|
|
// Set Baseline |
|
|
function setBaseline() { |
|
|
var box = gantt.confirm({ |
|
|
text: "Set Baseline for this gantt chart?", |
|
|
ok: "Yes", |
|
|
cancel: "No", |
|
|
callback: async function (result) { |
|
|
if (result) { |
|
|
// gantt.message("Yes!"); |
|
|
// send to API |
|
|
await setBaselineAPI(); |
|
|
} else { |
|
|
// gantt.message("No..."); |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
// Set Baseline Activity |
|
|
function setBaselineActivity(activity_id, name) { |
|
|
var box = gantt.confirm({ |
|
|
text: `Set Baseline for this activity <b>${name}</b>?`, |
|
|
ok: "Yes", |
|
|
cancel: "No", |
|
|
callback: async function (result) { |
|
|
if (result) { |
|
|
await setBaselineActivityAPI(activity_id); |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
async function importUpdate() { |
|
|
expandTask(); |
|
|
var allTasks = []; |
|
|
var taskCount = gantt.getTaskCount(); |
|
|
|
|
|
for (var i = 0; i < taskCount; i++) { |
|
|
var task = gantt.getTaskByIndex(i); |
|
|
allTasks.push(task); |
|
|
} |
|
|
|
|
|
$("body").addClass("loading"); |
|
|
const response = await gantt.ajax.post({ |
|
|
headers: { |
|
|
"Content-Type": "application/json", |
|
|
"Authorization": `Bearer ${token}` |
|
|
}, |
|
|
url: `${base_url}activity/import-update`, |
|
|
dataType: "json", |
|
|
data: JSON.stringify(allTasks) |
|
|
}).then(function (response) { |
|
|
$("body").removeClass("loading"); |
|
|
let res = response.responseText |
|
|
res = JSON.parse(res) |
|
|
}).catch(function (error) { |
|
|
$("body").removeClass("loading"); |
|
|
gantt.alert({ |
|
|
title: "Peringatan", |
|
|
type: "alert-error", |
|
|
text: "Update import gagal" |
|
|
}); |
|
|
}); |
|
|
} |
|
|
|
|
|
async function setBaselineActivityAPI(activity_id) { |
|
|
await importUpdate(); |
|
|
const res = await axiosInstance |
|
|
.get(ACTIVITY_SET_BASELINE_ACTIVITY_URL(activity_id), HEADER) |
|
|
.then(res => res) |
|
|
.catch((error) => error.response); |
|
|
if (res && res.status === 200) { |
|
|
gantt.message("Set baseline activity success!"); |
|
|
window.location.reload(); |
|
|
} else { |
|
|
$("body").removeClass("loading"); |
|
|
gantt.alert({ type: "error", text: "Failed to set baseline activity" }); |
|
|
} |
|
|
gantt.render(); |
|
|
} |
|
|
|
|
|
async function setBaselineAPI() { |
|
|
await importUpdate(); |
|
|
const res = await axiosInstance |
|
|
.get(ACTIVITY_SET_BASELINE_URL, HEADER) |
|
|
.then(res => res) |
|
|
.catch((error) => error.response); |
|
|
if (res && res.status === 200) { |
|
|
// $('#modal_gantt_setting').modal('hide'); |
|
|
// gantt.alert("Settings updated"); |
|
|
// gantt.message(result.data.message); |
|
|
gantt.message("Set baseline success!"); |
|
|
window.location.reload(); |
|
|
} |
|
|
else { |
|
|
$("body").removeClass("loading"); |
|
|
gantt.alert({ type: "error", text: "Failed to set baseline" }); |
|
|
} |
|
|
gantt.render(); |
|
|
} |
|
|
|
|
|
function setSynchronize() { |
|
|
if (!isBaselineSet) { |
|
|
// gantt.alert({ |
|
|
// title:"Synchronize to Report", |
|
|
// type:"alert-error", |
|
|
// text:"Please set baseline before continue." |
|
|
// }); |
|
|
gantt.confirm({ |
|
|
text: "Plase set baseline before continue.", |
|
|
ok: "Set Baseline", |
|
|
cancel: "Cancel", |
|
|
callback: async function (result) { |
|
|
if (result) { |
|
|
await setBaselineAPI(); |
|
|
} |
|
|
} |
|
|
}); |
|
|
return false; |
|
|
} |
|
|
|
|
|
var box = gantt.confirm({ |
|
|
text: "Synchronize to Report Activity?", |
|
|
ok: "Yes", |
|
|
cancel: "No", |
|
|
callback: async function (result) { |
|
|
if (result) { |
|
|
// gantt.message("Yes!"); |
|
|
// send to API |
|
|
await setSynchronizeAPI() |
|
|
} else { |
|
|
// gantt.message("No..."); |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
function updateSchedule() { |
|
|
$("body").addClass("loading"); |
|
|
return gantt.ajax.get({ |
|
|
headers: { |
|
|
"Content-Type": "application/json", |
|
|
"Authorization": `Bearer ${token}` |
|
|
}, |
|
|
url: base_url + "activity/update-schedule/" + ganttId |
|
|
}).then(function (response) { |
|
|
$("body").removeClass("loading"); |
|
|
window.location.reload(); |
|
|
}).catch(function (error) { |
|
|
$("body").removeClass("loading") |
|
|
gantt.alert({ |
|
|
title: "Peringatan", |
|
|
type: "alert-error", |
|
|
text: "Update activity gagal" |
|
|
}); |
|
|
}); |
|
|
} |
|
|
|
|
|
async function setSynchronizeAPI() { |
|
|
const res = await axiosInstance |
|
|
.get(ACTIVITY_SYNCHRONIZE_REPORT_URL, HEADER) |
|
|
.then(res => res) |
|
|
.catch((error) => error.response); |
|
|
|
|
|
if (res && res.status === 200) { |
|
|
// $('#modal_gantt_setting').modal('hide'); |
|
|
// gantt.alert("Settings updated"); |
|
|
// gantt.message(result.data.message); |
|
|
gantt.message("Synchronize to Report success!"); |
|
|
window.location.reload(); |
|
|
} |
|
|
else { |
|
|
gantt.alert({ type: "error", text: "Failed to Synchronize to Report" }); |
|
|
} |
|
|
gantt.render(); |
|
|
} |
|
|
|
|
|
|