You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piomint/app/static/app/js/dbcontrol.js

381 lines
14 KiB

// IndexedDB Funktionen
const dbName = 'myDB';
const dbVersion = 2;
let db;
//
// GRUND FUNKTIONEN FÜR DIE DATENBANK
//
// IndexedDB initialisieren
function initDB() {
return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName, dbVersion);
request.onupgradeneeded = function (event) {
db = event.target.result;
if (!db.objectStoreNames.contains('hours')) {
const store = db.createObjectStore('hours', {
keyPath: 'id',
autoIncrement: true,
});
// Spalten definieren
store.createIndex('createdate', 'createdate', { unique: false });
store.createIndex('date', 'date', { unique: false });
store.createIndex('duration', 'duration', { unique: false });
store.createIndex('type', 'type', { unique: false });
store.createIndex('status', 'status', { unique: false });
store.createIndex('sondertext', 'sondertext', { unique: false });
}
if (!db.objectStoreNames.contains('settings')) {
const settingsT = db.createObjectStore('settings', {
keyPath: 'id',
autoIncrement: true,
})
settingsT.createIndex('SettingsID', 'SettingsID', { unique: false });
settingsT.createIndex('SettingsValue', 'SettingsValue', { unique: false });
}
};
request.onsuccess = function (event) {
db = event.target.result;
resolve(db);
};
request.onerror = function (event) {
console.error('IndexedDB Fehler:', event.target.errorCode);
reject(event.target.errorCode);
};
});
}
// Neuer Eintrag in die IndexedDB
function addEntry(data, table) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([table], 'readwrite');
const store = transaction.objectStore(table);
data.createdate = new Date();
const request = store.add(data);
request.onsuccess = function () {
resolve(request.result);
};
request.onerror = function (event) {
reject('Fehler beim Hinzufügen des Eintrags:', event.target.error);
};
});
}
// Eintrag aktualisieren
function updateEntry(id, table, updatedData) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([table], 'readwrite');
const store = transaction.objectStore(table);
const getRequest = store.get(id);
getRequest.onsuccess = function (event) {
const data = event.target.result;
Object.assign(data, updatedData);
data.createdate = new Date(); // Aktualisiere das Änderungsdatum
const updateRequest = store.put(data);
updateRequest.onsuccess = function () {
resolve(data);
};
updateRequest.onerror = function (event) {
reject('Fehler beim Aktualisieren des Eintrags:', event.target.error);
};
};
getRequest.onerror = function (event) {
reject('Fehler beim Abrufen des Eintrags:', event.target.error);
};
});
}
// Eintrag löschen
function deleteEntry(id) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['hours'], 'readwrite');
const store = transaction.objectStore('hours');
const request = store.delete(id);
request.onsuccess = function () {
resolve(`Eintrag mit ID ${id} gelöscht.`);
};
request.onerror = function (event) {
reject('Fehler beim Löschen des Eintrags:', event.target.error);
};
});
}
// Einträge abrufen
function getAllEntries(table) {
return new Promise((resolve, reject) => {
const transaction = db.transaction([table], 'readonly');
const store = transaction.objectStore(table);
const request = store.getAll();
request.onsuccess = function () {
resolve(request.result);
};
request.onerror = function (event) {
reject('Fehler beim Abrufen der Einträge:', event.target.error);
};
});
}
// Neuen Eintrag verschlüsselt speichern
async function addEncryptedEntry(data) {
const key = await generateKey();
const { iv, encryptedData } = await encryptData(key, JSON.stringify(data));
return new Promise((resolve, reject) => {
const transaction = db.transaction(['hours'], 'readwrite');
const store = transaction.objectStore('hours');
const request = store.add({
iv: Array.from(iv), // IV muss auch gespeichert werden
encryptedData: Array.from(new Uint8Array(encryptedData)), // Encrypted data als Uint8Array speichern
});
request.onsuccess = function () {
resolve(request.result);
};
request.onerror = function (event) {
reject('Fehler beim Hinzufügen des verschlüsselten Eintrags:', event.target.error);
};
});
}
// Verschlüsselten Eintrag entschlüsseln
async function getDecryptedEntry(id) {
const key = await generateKey();
return new Promise((resolve, reject) => {
const transaction = db.transaction(['hours'], 'readonly');
const store = transaction.objectStore('hours');
const request = store.get(id);
request.onsuccess = async function () {
const entry = request.result;
if (entry) {
const iv = new Uint8Array(entry.iv);
const encryptedData = new Uint8Array(entry.encryptedData);
const decryptedData = await decryptData(key, iv, encryptedData);
resolve(JSON.parse(decryptedData));
} else {
reject('Eintrag nicht gefunden');
}
};
request.onerror = function (event) {
reject('Fehler beim Abrufen des verschlüsselten Eintrags:', event.target.error);
};
});
}
function durationDBtoForm(durationInMin) {
const hours = Math.floor(durationInMin / 60); // Ganze Stunden berechnen
const mins = durationInMin % 60; // Verbleibende Minuten berechnen
return [hours, mins]
}
//
// KOMBI FUNKTIONEN
// SIND VOR ALLEM HIER DAMIT SIE ZEITGLEICH GERENDERT WERDEN
//
// Die abgefragte Dauer in Minuten umrechnen und in hh:mm formatieren
function formatDuration(minutes, shortOutput = false) {
const hours = Math.floor(minutes / 60); // Ganze Stunden berechnen
const mins = minutes % 60; // Verbleibende Minuten berechnen
if (!shortOutput){
return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}`; // Stunden und Minuten formatieren
} else {
return `${String(hours)}:${String(mins)}`.replace(':30', ',5').replace(':0', ''); // Stunden und Minuten formatieren
}
}
// Datum für die gewünschte Ansicht formatieren
function formatDate(dateString) {
const date = new Date(dateString); // Konvertiere in ein Date-Objekt
const day = String(date.getDate()).padStart(2, '0'); // Tag
const month = String(date.getMonth() + 1).padStart(2, '0'); // Monat (getMonth() ist 0-basiert)
const year = String(date.getFullYear()).slice(-2); // Die letzten 2 Ziffern des Jahres
return `${day}.${month}.${year}`; // Format tt.mm.yy
}
// Einträge nach Monat und/oder Jahr filtern
function filterEntriesByMonthYear(month, year) {
return new Promise((resolve, reject) => {
const transaction = db.transaction(['hours'], 'readonly');
const store = transaction.objectStore('hours');
const request = store.getAll();
request.onsuccess = function () {
const allEntries = request.result;
// Filter nach Monat und Jahr
const filteredEntries = allEntries.filter(entry => {
const entryDate = new Date(entry.date); // Konvertiere das date-Feld in ein Date-Objekt
var actualYear = year;
const matchesMonth = month ? entryDate.getMonth() + 1 === month : true; // +1 da getMonth() 0-basiert ist
if (entryDate.getMonth() + 1 >= 9){
actualYear = actualYear - 1;
} else {
actualYear = actualYear;
};
const matchesYear = actualYear ? entryDate.getFullYear() === actualYear : true;
return matchesMonth && matchesYear;
});
resolve(filteredEntries);
};
request.onerror = function (event) {
reject('Fehler beim Abrufen der Einträge:', event.target.error);
};
});
}
// Tabelle auf dem Dashboard mit Infos füllen
function fillTableWithEntries(entries) {
const tableBody = document.getElementById('entriesTableBody');
entries.sort((a, b) => new Date(a.date) - new Date(b.date));
// Zuerst den Inhalt der Tabelle löschen (falls schon Daten da sind)
tableBody.innerHTML = '';
// Iteriere durch die Einträge und füge Zeilen hinzu
entries.forEach(entry => {
const row = document.createElement('tr');
//EVENTUELL MAL IN DER ZUKUNFT - UM EINTRÄGE ZU SEITE WISCHEN
// let startX = 0;
// let currentRow;
// row.addEventListener('touchstart', (e) => {
// startX = e.touches[0].clientX;
// currentRow = e.currentTarget;
// });
// row.addEventListener('touchmove', (e) => {
// const moveX = e.touches[0].clientX;
// if (startX - moveX > 50) {
// currentRow.classList.add('swipe-left');
// }
// });
// // Am Ende des Swipe, zeige den Löschen-Button
// row.addEventListener('touchend', () => {
// if (currentRow.classList.contains('swipe-left')) {
// currentRow.querySelector('.editCell').classList.remove('d-none')
// currentRow.querySelector('.delCell').classList.remove('d-none')
// currentRow.querySelector('.duration').classList.add('d-none')
// currentRow.querySelector('.date').classList.add('d-none')
// }
// });
// Spalte für die Dauer (duration)
const durationCell = document.createElement('td');
durationCell.classList.add('duration')
durationCell.textContent = formatDuration(entry.duration); // Dauer im hh:mm-Format
row.appendChild(durationCell);
// Spalte für das Datum (date)
const dateCell = document.createElement('td');
const entryDate = new Date(entry.date); // Konvertiere in ein Date-Objekt
dateCell.classList.add('date')
dateCell.textContent = formatDate(entry.date); // Datum im tt.mm.yy-Format
row.appendChild(dateCell);
// Spalte für den Typ (type) - wenn 3, dann zeige "Beschreibung" an
const typeCell = document.createElement('td');
if (entry.type === 3) {
typeCell.textContent = entry.sondertext; // Bei Type 3 zeige "Beschreibung" an
} else if (entry.type === 2) {
typeCell.textContent = 'LDC'; // Ansonsten zeige den Type-Wert
} else if (entry.type === 1) {
typeCell.textContent = 'Dienst'; // Ansonsten zeige den Type-Wert
}
row.appendChild(typeCell);
const editCell = document.createElement('td');
// editCell.classList.add('editCell')
// editCell.style = 'background-color: rgb(120,170,86); color: white;'
editCell.addEventListener('click', ()=>{
document.getElementById('editEntryID').value = entry.id;
document.getElementById('editStunden').value = durationDBtoForm(entry.duration)[0];
document.getElementById('editMinuten').value = durationDBtoForm(entry.duration)[1];
document.getElementById('editDatum').value = entry.date;
if (entry.type === 2) {
document.getElementById('editldcCheck').checked = true;
} else {
document.getElementById('editldcCheck').checked = false;
}
if (entry.type === 3) {
document.getElementById('editsonstigesCheck').checked = true;
document.getElementById('editsonstigesInput').value = entry.sondertext;
document.getElementById('edit-sonstiges-text').style.display = 'block';
} else {
document.getElementById('editsonstigesCheck').checked = false;
document.getElementById('editsonstigesInput').value = null;
document.getElementById('edit-sonstiges-text').style.display = 'none';
}
})
editCell.innerHTML = '<span class="btn btn-sm btn-secondary" data-bs-toggle="modal" data-bs-target="#editEntryModel" style="width: 40px; border-radius: 1rem; transform: rotate(180deg);">✐</span>';
row.appendChild(editCell)
// const delCell = document.createElement('td');
// delCell.classList.add('d-none')
// delCell.classList.add('delCell')
// delCell.style = 'background-color: red; color: white;'
// delCell.innerHTML = '<p style="margin: 0; padding: 0;">Delete</p>'
// row.appendChild(delCell)
// Füge die erstellte Zeile dem Tabellenkörper hinzu
tableBody.appendChild(row);
});
}
// Abgefragte Daten Zeiten summieren und filtern können
function sumDurations(data, type = null, roundToHalfHour = false) {
// Optionaler Filter nach dem Typ, falls ein Typ angegeben wurde
const filteredData = type !== null ? data.filter(item => item.type === type) : data;
// Berechnung der Summe der "duration"-Werte
let totalDuration = filteredData.reduce((sum, item) => sum + item.duration, 0);
// Optionales Runden auf halbe Stunden
if (roundToHalfHour) {
totalDuration = Math.round(totalDuration / 30) * 30;
}
return totalDuration;
}

Powered by TurnKey Linux.