187 lines
6.9 KiB
JavaScript
187 lines
6.9 KiB
JavaScript
let prevMonthBtn, nextMonthBtn, month
|
|
let curYear = new Date().getFullYear()
|
|
let curMonth = new Date().getMonth()
|
|
let curWeekDate = new Date()
|
|
|
|
function prevMonth() {
|
|
curMonth = curMonth - 1
|
|
if (curMonth < 0) {
|
|
curMonth += 12
|
|
curYear -= 1
|
|
}
|
|
updateTableMonthly()
|
|
}
|
|
function nextMonth() {
|
|
curMonth = curMonth + 1
|
|
if (curMonth >= 12) {
|
|
curMonth -= 12
|
|
curYear += 1
|
|
}
|
|
updateTableMonthly()
|
|
}
|
|
|
|
function updateTableMonthly() {
|
|
let year = curYear.toString().padStart(4, "0")
|
|
let month = (curMonth + 1).toString().padStart(2, "0")
|
|
let today = new Date()
|
|
let txt = MONTHS[curMonth]
|
|
if (today.getFullYear() !== curYear) {
|
|
txt += " " + year.toString().padStart(4, "0")
|
|
}
|
|
document.getElementById("month").innerText = txt
|
|
|
|
fetch(`stats/by-month/${year}/${month}/`).then(res => {
|
|
return res.json()
|
|
}).then(res => {
|
|
if (res.status !== "success") {
|
|
return
|
|
}
|
|
updateTable(res.data)
|
|
})
|
|
}
|
|
|
|
function updateTable(data) {
|
|
let totalWorked = data.clockings.map(c => c.total).reduce((a, b) => a + b, 0)
|
|
|
|
let parents = data.parents.filter(parent => parent.duration !== null && parent.is_productive)
|
|
|
|
let headers = document.getElementById("headers-table")
|
|
let table = document.getElementById("projects-table")
|
|
let projNames = table.querySelector(".project-names")
|
|
let projNums = table.querySelector(".project-nums")
|
|
let totDurations = table.querySelector(".total-durations")
|
|
let workingRatios = table.querySelector(".working-time-ratios")
|
|
let imputedRatios = table.querySelector(".imputed-time-ratios")
|
|
let sagexHours = table.querySelector(".sagex-hours")
|
|
let realSagexHours = table.querySelector(".real-sagex-hours")
|
|
let differences = table.querySelector(".sagex-diff")
|
|
table.querySelectorAll("tr").forEach(row => row.innerHTML = "")
|
|
|
|
let totalImputed = 0
|
|
parents.forEach(parent => {
|
|
totalImputed += +parent.duration
|
|
})
|
|
headers.querySelector(".total-clocking").innerText = formatDuration(totalWorked)
|
|
headers.querySelector(".total-duration").innerText = formatDuration(totalImputed)
|
|
|
|
let sagexHoursTemplate = getTemplate("sagex-hours")
|
|
|
|
let totalSagex = 0
|
|
let totalRealSagex = 0
|
|
parents.forEach(parent => {
|
|
let duration = +parent.duration
|
|
let name = document.createElement("th")
|
|
name.innerText = parent.name
|
|
projNames.appendChild(name)
|
|
projNums.insertCell(-1).innerText = parent.project_num
|
|
table.querySelector(".clocking").insertCell(-1)
|
|
totDurations.insertCell(-1).innerText = formatDuration(duration)
|
|
|
|
let ratioWorking = duration / totalWorked
|
|
let ratioImputed = duration / totalImputed
|
|
workingRatios.insertCell(-1).innerText = formatPercentage(ratioWorking)
|
|
imputedRatios.insertCell(-1).innerText = formatPercentage(ratioImputed)
|
|
let sagexDuration = duration * totalWorked / totalImputed
|
|
totalSagex += sagexDuration
|
|
let sagexCell = sagexHours.insertCell(-1)
|
|
sagexCell.innerText = formatDuration(sagexDuration)
|
|
sagexCell.dataset.duration = sagexDuration
|
|
|
|
let td = sagexHoursTemplate.cloneNode(true)
|
|
let [h, m, s] = parent.real_sagex_hours.split(":")
|
|
let hoursInput = td.querySelector("input.hours")
|
|
let minutesInput = td.querySelector("input.minutes")
|
|
hoursInput.value = h
|
|
minutesInput.value = m
|
|
let timeout = null
|
|
minutesInput.addEventListener("input", () => reformatTime(minutesInput))
|
|
td.addEventListener("change", () => {
|
|
if (timeout !== null) {
|
|
clearTimeout(timeout)
|
|
}
|
|
timeout = setTimeout(() => {
|
|
updateSagex(parent.id, td)
|
|
}, 1000)
|
|
})
|
|
realSagexHours.appendChild(td)
|
|
let real = (+h)*60 + (+m)
|
|
let diff = real - sagexDuration
|
|
differences.insertCell(-1).innerText = formatDuration(diff)
|
|
totalRealSagex += real
|
|
})
|
|
headers.querySelector(".sagex-hours-total").innerText = formatDuration(totalSagex)
|
|
headers.querySelector(".real-sagex-hours-total").innerText = formatDuration(totalRealSagex)
|
|
headers.querySelector(".sagex-diff-total").innerText = formatDuration(totalRealSagex - totalSagex)
|
|
}
|
|
|
|
function reformatTime(input) {
|
|
let value = input.value
|
|
if (value.length === 1) {
|
|
input.value = "0" + value
|
|
} else if (value.length > 2) {
|
|
input.value = value.slice(value.length - 2)
|
|
}
|
|
}
|
|
|
|
function getDuration(td) {
|
|
let hours = +td.querySelector(".hours").value
|
|
let minutes = +td.querySelector(".minutes").value
|
|
return hours * 60 + minutes
|
|
}
|
|
|
|
function updateSagex(id, cell) {
|
|
let minutesInput = cell.querySelector(".minutes")
|
|
reformatTime(minutesInput)
|
|
|
|
let newDuration = getDuration(cell)
|
|
let year = curYear.toString().padStart(4, "0")
|
|
let month = (curMonth + 1).toString().padStart(2, "0")
|
|
let date = `${year}-${month}`
|
|
let fd = new FormData()
|
|
fd.set("minutes", newDuration)
|
|
|
|
req(`/sagex/${id}/${date}/`, {
|
|
method: "POST",
|
|
body: fd
|
|
}).then(res => {
|
|
return res.json()
|
|
}).then(res => {
|
|
if (res.status === "success") {
|
|
cell.classList.add("saved")
|
|
cell.addEventListener("animationend", () => {
|
|
cell.classList.remove("saved")
|
|
}, {once: true})
|
|
let theoreticalRow = document.querySelector("#projects-table tr.sagex-hours")
|
|
let realRow = document.querySelector("#projects-table tr.real-sagex-hours")
|
|
let diffRow = document.querySelector("#projects-table tr.sagex-diff")
|
|
let totalRealCell = document.querySelector("#headers-table tr.real-sagex-hours .real-sagex-hours-total")
|
|
let totalDiffCell = document.querySelector("#headers-table tr.sagex-diff .sagex-diff-total")
|
|
|
|
let durationsTheory = Array.from(theoreticalRow.cells).map(c => +c.dataset.duration)
|
|
let durationsReal = Array.from(realRow.cells).map(getDuration)
|
|
let totalTheory = durationsTheory.reduce((a, b) => a + b, 0)
|
|
let totalReal = durationsReal.reduce((a, b) => a + b, 0)
|
|
let totalDiff = totalReal - totalTheory
|
|
totalRealCell.innerText = formatDuration(totalReal)
|
|
totalDiffCell.innerText = formatDuration(totalDiff)
|
|
|
|
let theory = +theoreticalRow.cells[cell.cellIndex].dataset.duration
|
|
let diff = newDuration - theory
|
|
diffRow.cells[cell.cellIndex].innerText = formatDuration(diff)
|
|
|
|
} else {
|
|
alert(res.error)
|
|
}
|
|
})
|
|
}
|
|
|
|
window.addEventListener("load", () => {
|
|
prevMonthBtn = document.getElementById("prev-month")
|
|
nextMonthBtn = document.getElementById("next-month")
|
|
month = document.getElementById("month")
|
|
|
|
prevMonthBtn.addEventListener("click", () => prevMonth())
|
|
nextMonthBtn.addEventListener("click", () => nextMonth())
|
|
|
|
updateTableMonthly()
|
|
}) |