343 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Fertigungsbaum</title>
<script src="/backend/xlsx/xlsx.full.min.js"></script>
<script src="/backend/handsontable/handsontable/dist/handsontable.full.min.js"></script>
<link rel="stylesheet" href="/backend/handsontable/handsontable/dist/handsontable.full.min.css">
<link rel="stylesheet" href="/backend/jstree/dist/themes/default/style.min.css" />
<script src="/backend/jquery/jquery-3.7.1.min.js"></script>
<script src="/backend/jstree/dist/jstree.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
background-color: #f4f4f4;
}
#tree-container {
width: 60%;
max-width: 800px;
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
#tree {
max-height: 600px;
overflow-y: auto;
}
.button-container {
position: fixed;
bottom: 20px;
right: 20px;
display: flex;
gap: 10px;
}
.button-container button {
background-color: red;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
.modal {
display: none;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 5px;
width: 600px;
text-align: center;
position: relative;
}
.close {
cursor: pointer;
position: absolute;
right: 10px;
top: 10px;
font-size: 20px;
}
#import-table {
width: 100%;
margin-top: 10px;
}
/* Neues Modal für die Config.html */
#config-modal iframe {
width: 100%;
height: 100%;
border: none;
}
#config-modal {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background-color: rgba(0,0,0,0.6); /* halbtransparenter Hintergrund */
display: none; /* per default ausgeblendet */
justify-content: center;
align-items: center;
z-index: 9999; /* ganz oben anzeigen */
}
/* Der weiße Container im Overlay: hier auf 100% */
#config-modal-content {
width: 100%;
height: 100%;
background-color: #fff;
position: relative; /* für den Close-Button */
}
/* Kopfbereich mit Title + Close-Button (optional) */
#config-modal-header {
background: #f2f2f2;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
#config-modal-header h2 {
margin: 0;
}
#config-modal-close {
font-weight: bold;
cursor: pointer;
}
/* Körper: hier das iframe auf Vollbild */
#config-modal-body {
width: 100%;
height: calc(100% - 50px); /* 50px = ungefährer Header-Höhenwert */
overflow: hidden; /* Kein Scrollen auf dem Container selbst */
}
</style>
</head>
<body>
<div id="config-modal">
<div id="config-modal-content">
<div id="config-modal-header">
<h2>Konfiguration</h2>
<span id="config-modal-close" onclick="closeConfigModal()">[X]</span>
</div>
<div id="config-modal-body">
<iframe id="config-iframe"></iframe>
</div>
</div>
</div>
<div id="tree-container">
<h2 style="text-align: center;">Fertigungsbaum</h2>
<div id="tree"></div>
</div>
<div class="button-container">
<button onclick="exportExcel()">Excel Export</button>
<button onclick="openImportModal()">Excel Import</button>
</div>
<!-- Import-Modal -->
<div id="import-modal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeImportModal()">&times;</span>
<h3>Excel Datei hochladen</h3>
<input type="file" id="file-input" accept=".xlsx">
<div id="import-table"></div>
<button onclick="importExcelData()">Importieren</button>
<button onclick="sendExcelData()">Senden</button>
</div>
</div>
<!-- Neues Modal für die Config.html -->
<div id="config-modal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeConfigModal()">&times;</span>
<!-- Hier das iframe, das Config.html lädt -->
<iframe id="config-iframe" src=""></iframe>
</div>
</div>
<script>
let rawTable;
const url = sessionStorage.getItem("url");
function fetchTreeData() {
fetch(url + '/backend/api/getStations', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
body: JSON.stringify({'station': sessionStorage.getItem("stationNumber")})
})
.then(response => response.json())
.then(data => {
let treeData = buildJsTree(data);
$('#tree').jstree({ 'core': { 'data': treeData } });
})
.catch(error => console.error('Fehler beim Laden der Daten:', error));
}
function buildJsTree(data) {
return data.map(node => ({
id: node.id,
text: node.id + " | " + node.text,
children: node.children ? buildJsTree(node.children) : []
}));
}
function exportExcel() {
fetch(url + '/backend/api/getStationExport', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({'station': sessionStorage.getItem("stationNumber")})
})
.then(response => response.json())
.then(data => {
data.sort((a, b) =>
a.line_nr.localeCompare(b.line_nr) ||
a.line_bez.localeCompare(b.line_bez) ||
a.ma_grp_nr.localeCompare(b.ma_grp_nr) ||
a.ma_grp_bez.localeCompare(b.ma_grp_bez) ||
a.kap_nr.localeCompare(b.kap_nr) ||
a.kap_bez.localeCompare(b.kap_bez)
);
const worksheet = XLSX.utils.json_to_sheet(data, {
header: ["line_nr", "line_bez", "ma_grp_nr", "ma_grp_bez", "kap_nr", "kap_bez"]
});
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Export");
XLSX.writeFile(workbook, "StationsExport.xlsx");
})
.catch(error => {
console.error('Fehler beim Excel-Export:', error);
alert('Fehler beim Excel-Export: ' + error.message);
});
}
function importExcelData() {
const fileInput = document.getElementById("file-input");
if (!fileInput.files.length) return;
const reader = new FileReader();
reader.onload = function (event) {
const workbook = XLSX.read(event.target.result, { type: "binary" });
const sheet = workbook.Sheets[workbook.SheetNames[0]];
// Rohdaten als Objekte
const data = XLSX.utils.sheet_to_json(sheet, { defval: "" });
// ✅ Leere Zeilen ignorieren
rawTable = data.filter(row =>
Object.values(row).some(
val => val !== null && val !== undefined && String(val).trim() !== ""
)
);
if (rawTable.length === 0) {
alert("Keine gültigen Daten gefunden.");
return;
}
const container = document.getElementById("import-table");
container.innerHTML = ""; // wichtig bei erneutem Import
new Handsontable(container, {
data: rawTable,
colHeaders: Object.keys(rawTable[0]),
rowHeaders: true,
width: "100%",
height: 300,
licenseKey: "non-commercial-and-evaluation"
});
};
reader.readAsBinaryString(fileInput.files[0]);
}
function sendExcelData() {
const stationNumber = sessionStorage.getItem("stationNumber") || "TEST";
const filteredData = rawTable.map(item => ({
line_nr: item.line_nr,
line_bez: item.line_bez,
ma_grp_nr: item.ma_grp_nr,
ma_grp_bez: item.ma_grp_bez,
kap_nr: item.kap_nr,
kap_bez: item.kap_bez
}));
let sendata = JSON.stringify({
station: stationNumber,
data: filteredData
});
console.log(sendata);
fetch(url + '/backend/api/updateStations', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: sendata
})
//.then(response => response.json())
.then(result => alert("Daten erfolgreich gesendet!"))
.catch(error => alert("Fehler beim Senden der Daten: " + error.message));
}
// Modal-Steuerung für den Import-Dialog
function openImportModal() {
document.getElementById("import-modal").style.display = "flex";
}
function closeImportModal() {
document.getElementById("import-modal").style.display = "none";
}
// Modal-Steuerung für das Config-Dialog
function openConfigModal() {
document.getElementById("config-modal").style.display = "flex";
}
function closeConfigModal() {
document.getElementById("config-modal").style.display = "none";
}
$(document).ready(function() {
fetchTreeData();
$('#tree').on("dblclick.jstree", function (e) {
let node = $('#tree').jstree(true).get_node(e.target);
// Nur wenn kein weiterer Kindknoten vorhanden ist
if (node && node.children.length === 0) {
sessionStorage.setItem("selectedStation", node.id);
// Hier iframe-Source setzen, ggf. mit Parametern
let iframe = document.getElementById("config-iframe");
iframe.src = url + "/backend/Config.html?station=" + node.id;
// Modal öffnen
openConfigModal();
}
});
});
</script>
</body>
</html>