787 lines
40 KiB
HTML
787 lines
40 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>ERP EDI Bridge | VDA ↔ EDIFACT</title>
|
||
<link rel="stylesheet" href="styles.css">
|
||
<!-- Fonts -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&family=Fira+Code&display=swap"
|
||
rel="stylesheet">
|
||
|
||
<!-- Icons (External) - Error Handled -->
|
||
<script src="https://unpkg.com/lucide@latest"></script>
|
||
<script>
|
||
window.onerror = function (msg, url, line) {
|
||
console.error('Global Error: ' + msg + '\nline: ' + line);
|
||
return false;
|
||
};
|
||
</script>
|
||
</head>
|
||
|
||
<body>
|
||
<div class="dashboard">
|
||
<header>
|
||
<h1>ERP EDI Bridge</h1>
|
||
<p class="subtitle">Konvertieren Sie VDA 4913, 4905 und EDIFACT Nachrichten</p>
|
||
</header>
|
||
|
||
<!-- ═══ Page Navigation ═══ -->
|
||
<nav class="page-nav">
|
||
<button class="page-nav-btn active" data-page="converter" onclick="app.showPage('converter')">
|
||
<i data-lucide="repeat"></i>
|
||
Converter
|
||
</button>
|
||
<button class="page-nav-btn" data-page="viewer" onclick="app.showPage('viewer')">
|
||
<i data-lucide="file-text"></i>
|
||
EDI Viewer
|
||
</button>
|
||
<button class="page-nav-btn" data-page="editor" onclick="app.showPage('editor')">
|
||
<i data-lucide="edit-3"></i>
|
||
Editor
|
||
</button>
|
||
<button class="page-nav-btn" data-page="history" onclick="app.showPage('history')">
|
||
<i data-lucide="database"></i>
|
||
Historie
|
||
</button>
|
||
<button class="page-nav-btn" data-page="settings" onclick="app.showPage('settings')">
|
||
<i data-lucide="settings"></i>
|
||
Settings
|
||
</button>
|
||
</nav>
|
||
|
||
<!-- Config Upload (Global) -->
|
||
<div class="config-bar" style="max-width: 1200px; margin: 0 auto 20px auto;">
|
||
<div class="config-status" id="configStatus">
|
||
<i data-lucide="settings-2"></i>
|
||
<span>Keine Konfiguration geladen</span>
|
||
</div>
|
||
<button class="btn-secondary" onclick="document.getElementById('configInput').click()">
|
||
<i data-lucide="upload"></i>
|
||
Konfig laden
|
||
</button>
|
||
<button class="btn-secondary" id="btnSaveConfig" onclick="app.saveConfig()" style="display:none">
|
||
<i data-lucide="save"></i>
|
||
Konfig speichern
|
||
</button>
|
||
<input type="file" id="configInput" accept=".txt,.ini,.cfg" class="hidden">
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: CONVERTER -->
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<main class="main-card page-content" id="pageConverter">
|
||
|
||
<!-- Mode Toggle – 4 modes -->
|
||
<div class="mode-toggle">
|
||
<button id="btnOutboundBosch" class="mode-btn active" onclick="app.setMode('outbound-bosch')">
|
||
<i data-lucide="arrow-up-right"></i>
|
||
VDA 4913 → Bosch DESADV
|
||
</button>
|
||
<button id="btnOutboundZf" class="mode-btn" onclick="app.setMode('outbound-zf')">
|
||
<i data-lucide="arrow-up-right"></i>
|
||
VDA 4913 → ZF DESADV
|
||
</button>
|
||
<button id="btnOutboundIfm" class="mode-btn" onclick="app.setMode('outbound-ifm')">
|
||
<i data-lucide="arrow-up-right"></i>
|
||
VDA 4913 → IFM DELVRY03
|
||
</button>
|
||
<button id="btnInboundBosch" class="mode-btn" onclick="app.setMode('inbound-bosch')">
|
||
<i data-lucide="arrow-down-left"></i>
|
||
DELFOR → VDA 4905
|
||
</button>
|
||
<button id="btnInboundIfm" class="mode-btn" onclick="app.setMode('inbound-ifm')">
|
||
<i data-lucide="arrow-down-left"></i>
|
||
IFM DELFOR → VDA 4905
|
||
</button>
|
||
<button id="btnInboundInvrpt" class="mode-btn" onclick="app.setMode('inbound-invrpt')">
|
||
<i data-lucide="arrow-down-left"></i>
|
||
INVRPT → VDA 4913
|
||
</button>
|
||
<button id="btnValidateEdifact" class="mode-btn" onclick="app.setMode('validate-edifact')">
|
||
<i data-lucide="check-circle"></i>
|
||
EDIFACT Validieren
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Drop Zone -->
|
||
<div id="dropZone" class="drop-zone">
|
||
<i data-lucide="upload-cloud"></i>
|
||
<h3>Datei hier ablegen oder klicken</h3>
|
||
<p id="dropText">VDA 4913 Datei auswählen für Konvertierung</p>
|
||
<input type="file" id="fileInput" class="hidden">
|
||
</div>
|
||
|
||
<!-- Enrichment Section (shown after VDA upload in outbound-bosch mode) -->
|
||
<div id="enrichmentSection" class="enrichment-section">
|
||
|
||
<!-- NAD Segment Editor -->
|
||
<div class="preview-header" style="margin-bottom: 20px;">
|
||
<h2>Partneradressen (NAD Segmente)</h2>
|
||
<span class="badge badge-edi" id="nadSourceBadge">Manuell</span>
|
||
</div>
|
||
<div class="nad-grid">
|
||
<!-- Buyer (BY) -->
|
||
<div class="nad-card">
|
||
<div class="nad-card-header"><span class="nad-qualifier">BY</span><span>Käufer (Buyer)</span>
|
||
</div>
|
||
<label>ID <input type="text" id="nad-by-id" class="nad-input" value="5060"></label>
|
||
<label>Qualifier <input type="text" id="nad-by-qual" class="nad-input" value="92"></label>
|
||
<label>Firma <input type="text" id="nad-by-name" class="nad-input wide"
|
||
value="Robert Bosch spol. s.r.o."></label>
|
||
<label>Firma 2 <input type="text" id="nad-by-name2" class="nad-input wide" value=""></label>
|
||
<label>Straße <input type="text" id="nad-by-street" class="nad-input wide"
|
||
value="Roberta Bosche 2678"></label>
|
||
<label>Stadt <input type="text" id="nad-by-city" class="nad-input"
|
||
value="Ceske Budejovicen"></label>
|
||
<label>PLZ <input type="text" id="nad-by-zip" class="nad-input" value="37004"></label>
|
||
<label>Land <input type="text" id="nad-by-country" class="nad-input" value="CZ"
|
||
maxlength="2"></label>
|
||
</div>
|
||
|
||
<!-- Seller (SE) -->
|
||
<div class="nad-card">
|
||
<div class="nad-card-header"><span class="nad-qualifier">SE</span><span>Lieferant
|
||
(Seller)</span></div>
|
||
<label>ID <input type="text" id="nad-se-id" class="nad-input" value="0000062671"></label>
|
||
<label>Qualifier <input type="text" id="nad-se-qual" class="nad-input" value="92"></label>
|
||
<label>Firma <input type="text" id="nad-se-name" class="nad-input wide"
|
||
value="Roechling Precision Components"></label>
|
||
<label>Firma 2 <input type="text" id="nad-se-name2" class="nad-input wide" value=""></label>
|
||
<label>Straße <input type="text" id="nad-se-street" class="nad-input wide"
|
||
value="Winter-Ring 3"></label>
|
||
<label>Stadt <input type="text" id="nad-se-city" class="nad-input" value="Weidenberg"></label>
|
||
<label>PLZ <input type="text" id="nad-se-zip" class="nad-input" value="95466"></label>
|
||
<label>Land <input type="text" id="nad-se-country" class="nad-input" value="DE"
|
||
maxlength="2"></label>
|
||
</div>
|
||
|
||
<!-- Ship-To (ST) -->
|
||
<div class="nad-card">
|
||
<div class="nad-card-header"><span class="nad-qualifier">ST</span><span>Warenempfänger
|
||
(Ship-To)</span></div>
|
||
<label>ID <input type="text" id="nad-st-id" class="nad-input" value="5060"></label>
|
||
<label>Qualifier <input type="text" id="nad-st-qual" class="nad-input" value="92"></label>
|
||
<label>Firma <input type="text" id="nad-st-name" class="nad-input wide"
|
||
value="Robert Bosch spol. s.r.o."></label>
|
||
<label>Firma 2 <input type="text" id="nad-st-name2" class="nad-input wide" value=""></label>
|
||
<label>Straße <input type="text" id="nad-st-street" class="nad-input wide"
|
||
value="Roberta Bosche 2678"></label>
|
||
<label>Stadt <input type="text" id="nad-st-city" class="nad-input"
|
||
value="Ceske Budejovicen"></label>
|
||
<label>PLZ <input type="text" id="nad-st-zip" class="nad-input" value="37004"></label>
|
||
<label>Land <input type="text" id="nad-st-country" class="nad-input" value="CZ"
|
||
maxlength="2"></label>
|
||
</div>
|
||
|
||
<!-- Ship-From (SF) -->
|
||
<div class="nad-card">
|
||
<div class="nad-card-header"><span class="nad-qualifier">SF</span><span>Versender
|
||
(Ship-From)</span></div>
|
||
<label>ID <input type="text" id="nad-sf-id" class="nad-input" value="0000062671"></label>
|
||
<label>Qualifier <input type="text" id="nad-sf-qual" class="nad-input" value="92"></label>
|
||
<label>Firma <input type="text" id="nad-sf-name" class="nad-input wide"
|
||
value="Roechling Precision Components"></label>
|
||
<label>Firma 2 <input type="text" id="nad-sf-name2" class="nad-input wide" value=""></label>
|
||
<label>Straße <input type="text" id="nad-sf-street" class="nad-input wide"
|
||
value="Winter-Ring 3"></label>
|
||
<label>Stadt <input type="text" id="nad-sf-city" class="nad-input" value="Weidenberg"></label>
|
||
<label>PLZ <input type="text" id="nad-sf-zip" class="nad-input" value="95466"></label>
|
||
<label>Land <input type="text" id="nad-sf-country" class="nad-input" value="DE"
|
||
maxlength="2"></label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Material & Weight Enrichment -->
|
||
<div class="preview-header" style="margin-top: 40px;">
|
||
<h2>Positionen & Gewichte</h2>
|
||
<span class="badge badge-vda">VDA 4913</span>
|
||
</div>
|
||
<p class="subtitle">Artikel- und Packmittelgewichte können hier angepasst werden.</p>
|
||
<div class="table-container">
|
||
<table id="enrichmentTable">
|
||
<thead>
|
||
<tr>
|
||
<th>Kunden-Mat.</th>
|
||
<th>Lieferanten-Mat.</th>
|
||
<th>Menge</th>
|
||
<th>Einheit</th>
|
||
<th>Artikelgewicht (kg/Stk)</th>
|
||
<th>Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Packaging Weight & Dimensions Table -->
|
||
<div class="preview-header" style="margin-top: 30px;">
|
||
<h2>Packmittel (Gewichte & Maße)</h2>
|
||
</div>
|
||
<p class="subtitle">Alle Felder sind pflicht in DESADV. Fehlende Werte über Konfig-Datei ergänzen.</p>
|
||
<div class="table-container">
|
||
<table id="packagingTable">
|
||
<thead>
|
||
<tr>
|
||
<th>Packmittel (Kd)</th>
|
||
<th>Packmittel (Lief)</th>
|
||
<th>Anz.</th>
|
||
<th>Gewicht (kg)</th>
|
||
<th>Länge (cm)</th>
|
||
<th>Breite (cm)</th>
|
||
<th>Höhe (cm)</th>
|
||
<th>Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div style="margin-top: 30px; text-align: right;">
|
||
<button class="btn-primary" onclick="app.generateOutput()">
|
||
<i data-lucide="zap"></i>
|
||
JETZT KONVERTIEREN
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Result Section -->
|
||
<div id="resultSection" class="result-section">
|
||
<!-- Stats Grid -->
|
||
<div id="stats-grid" class="stats-grid"></div>
|
||
|
||
<div class="preview-header">
|
||
<h2 id="resultTitle">Konvertierungsergebnis</h2>
|
||
<div class="viewer-actions">
|
||
<button class="btn-secondary" onclick="app.viewResult()">
|
||
<i data-lucide="eye"></i>
|
||
View
|
||
</button>
|
||
<button class="btn-secondary" onclick="app.editResult()">
|
||
<i data-lucide="edit-3"></i>
|
||
Edit
|
||
</button>
|
||
<button class="btn-primary" onclick="app.downloadResult()">
|
||
<i data-lucide="download"></i>
|
||
Download
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<pre id="previewArea"></pre>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: SETTINGS -->
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<main class="main-card page-content" id="pageSettings" style="display:none">
|
||
<h2 class="settings-title">
|
||
<i data-lucide="folder-search"></i>
|
||
Ankommende Dateien (Folder Watch)
|
||
</h2>
|
||
<p class="subtitle" style="margin-bottom: 30px;">Überwacht einen Netzwerkordner auf neue Dateien,
|
||
konvertiert sie automatisch und schreibt die Ergebnisse in den Output-Ordner.</p>
|
||
|
||
<!-- General Settings & ID Mapping -->
|
||
<div class="log-section" style="margin-top: 40px;">
|
||
<h2 class="settings-title">
|
||
<i data-lucide="user-check"></i>
|
||
VDA 711 ID-Umschlüsselung
|
||
</h2>
|
||
<p class="subtitle" style="margin-bottom: 20px;">
|
||
Weisen Sie extrahierten IDs (Datenempfänger) eine eigene Kundennummer für den VDA 711 Header zu.
|
||
</p>
|
||
|
||
<div class="mapping-editor">
|
||
<div class="folder-input-row" style="margin-bottom: 20px;">
|
||
<input type="text" id="newIdMapOriginal" class="folder-path-input"
|
||
placeholder="Alt (z.B. 8810)" style="max-width: 200px;">
|
||
<input type="text" id="newIdMapTarget" class="folder-path-input"
|
||
placeholder="Neu (z.B. 10305)" style="max-width: 200px;">
|
||
<button class="btn-primary" onclick="app.addIdMapping711()">
|
||
<i data-lucide="plus"></i>
|
||
Hinzufügen
|
||
</button>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<table id="idMapping711Table">
|
||
<thead>
|
||
<tr>
|
||
<th>Extrahierte ID (Alt)</th>
|
||
<th>Eigene ID (Neu)</th>
|
||
<th style="width: 100px;">Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<!-- Populated by JS -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Electron notice -->
|
||
<div id="electronNotice" class="electron-notice" style="display:none">
|
||
<i data-lucide="alert-triangle"></i>
|
||
<span>Ordnerüberwachung ist nur in der Electron-App verfügbar. Bitte starten Sie die App mit
|
||
<code>npm start</code>.</span>
|
||
</div>
|
||
|
||
<!-- Folder Config -->
|
||
<div class="settings-grid">
|
||
<div class="settings-card">
|
||
<div class="settings-card-header">
|
||
<i data-lucide="folder-input"></i>
|
||
<span>Input-Ordner</span>
|
||
</div>
|
||
<div class="folder-input-row">
|
||
<input type="text" id="inputDirPath" class="folder-path-input"
|
||
placeholder="z.B. \\server\edi\input" readonly>
|
||
<button class="btn-secondary" id="btnSelectInput" onclick="app.selectInputFolder()">
|
||
<i data-lucide="folder-open"></i>
|
||
Wählen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="settings-card">
|
||
<div class="settings-card-header">
|
||
<i data-lucide="folder-output"></i>
|
||
<span>Output-Ordner</span>
|
||
</div>
|
||
<div class="folder-input-row">
|
||
<input type="text" id="outputDirPath" class="folder-path-input"
|
||
placeholder="z.B. \\server\edi\output" readonly>
|
||
<button class="btn-secondary" id="btnSelectOutput" onclick="app.selectOutputFolder()">
|
||
<i data-lucide="folder-open"></i>
|
||
Wählen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Watcher Controls -->
|
||
<div class="watcher-controls">
|
||
<div class="watcher-status-display">
|
||
<span class="watcher-status-dot" id="watcherDot"></span>
|
||
<span id="watcherStatusText">Gestoppt</span>
|
||
</div>
|
||
<div class="watcher-buttons">
|
||
<button class="btn-primary btn-start" id="btnStartWatcher" onclick="app.startWatcher()">
|
||
<i data-lucide="play"></i>
|
||
Starten
|
||
</button>
|
||
<button class="btn-secondary btn-pause" id="btnPauseWatcher" onclick="app.pauseWatcher()" disabled>
|
||
<i data-lucide="pause"></i>
|
||
Pausieren
|
||
</button>
|
||
<button class="btn-secondary btn-resume" id="btnResumeWatcher" onclick="app.resumeWatcher()"
|
||
style="display:none">
|
||
<i data-lucide="play"></i>
|
||
Fortsetzen
|
||
</button>
|
||
<button class="btn-secondary btn-stop" id="btnStopWatcher" onclick="app.stopWatcher()" disabled>
|
||
<i data-lucide="square"></i>
|
||
Stoppen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Outbound Folder Config -->
|
||
<div class="log-section" style="margin-top: 40px;">
|
||
<h2 class="settings-title">
|
||
<i data-lucide="folder-search"></i>
|
||
Ausgehende Dateien (Folder Watch)
|
||
</h2>
|
||
<p class="subtitle" style="margin-bottom: 20px;">
|
||
Überwacht einen Netzwerkordner auf ausgehende Dateien, konvertiert sie automatisch und schreibt die Ergebnisse in den Output-Ordner.
|
||
</p>
|
||
|
||
<div class="settings-grid">
|
||
<div class="settings-card">
|
||
<div class="settings-card-header">
|
||
<i data-lucide="folder-input"></i>
|
||
<span>Input-Ordner (Ausgehend)</span>
|
||
</div>
|
||
<div class="folder-input-row">
|
||
<input type="text" id="outboundInputPath" class="folder-path-input"
|
||
placeholder="z.B. \\server\edi\outbound_in" readonly>
|
||
<button class="btn-secondary" onclick="app.selectOutboundInput()">
|
||
<i data-lucide="folder-open"></i>
|
||
Wählen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="settings-card">
|
||
<div class="settings-card-header">
|
||
<i data-lucide="folder-output"></i>
|
||
<span>Output-Ordner (Ausgehend)</span>
|
||
</div>
|
||
<div class="folder-input-row">
|
||
<input type="text" id="outboundOutputPath" class="folder-path-input"
|
||
placeholder="z.B. \\server\edi\outbound_out" readonly>
|
||
<button class="btn-secondary" onclick="app.selectOutboundOutput()">
|
||
<i data-lucide="folder-open"></i>
|
||
Wählen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="watcher-controls">
|
||
<div class="watcher-status-display">
|
||
<span class="watcher-status-dot" id="outboundWatcherDot"></span>
|
||
<span id="outboundWatcherStatusText">Gestoppt</span>
|
||
</div>
|
||
<div class="watcher-buttons">
|
||
<button class="btn-primary btn-start" id="btnStartOutboundWatcher"
|
||
onclick="app.startOutboundWatcher()">
|
||
<i data-lucide="play"></i>
|
||
Starten
|
||
</button>
|
||
<button class="btn-secondary btn-pause" id="btnPauseOutboundWatcher"
|
||
onclick="app.pauseOutboundWatcher()" disabled>
|
||
<i data-lucide="pause"></i>
|
||
Pausieren
|
||
</button>
|
||
<button class="btn-secondary btn-resume" id="btnResumeOutboundWatcher"
|
||
onclick="app.resumeOutboundWatcher()" style="display:none">
|
||
<i data-lucide="play"></i>
|
||
Fortsetzen
|
||
</button>
|
||
<button class="btn-secondary btn-stop" id="btnStopOutboundWatcher" onclick="app.stopOutboundWatcher()"
|
||
disabled>
|
||
<i data-lucide="square"></i>
|
||
Stoppen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Werksnummer Watcher Controls (New Section) -->
|
||
<div class="log-section" style="margin-top: 40px;">
|
||
<h2 class="settings-title">
|
||
<i data-lucide="file-text"></i>
|
||
Werksnummer Umbenennung
|
||
</h2>
|
||
<p class="subtitle" style="margin-bottom: 20px;">
|
||
Überwacht VDA-Dateien (RA_VDA*) und benennt sie basierend auf der Werksnummer in Satzart 512 um
|
||
(100 → LEIFERS, 280 → PITESTI).
|
||
</p>
|
||
|
||
<div class="settings-grid">
|
||
<div class="settings-card">
|
||
<div class="settings-card-header">
|
||
<i data-lucide="folder-input"></i>
|
||
<span>Input-Ordner (Werksnummer)</span>
|
||
</div>
|
||
<div class="folder-input-row">
|
||
<input type="text" id="werksInputPath" class="folder-path-input"
|
||
placeholder="Input für Umbenennung" readonly>
|
||
<button class="btn-secondary" onclick="app.selectWerksInput()">
|
||
<i data-lucide="folder-open"></i>
|
||
Wählen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="settings-card">
|
||
<div class="settings-card-header">
|
||
<i data-lucide="folder-output"></i>
|
||
<span>Output-Ordner (Werksnummer)</span>
|
||
</div>
|
||
<div class="folder-input-row">
|
||
<input type="text" id="werksOutputPath" class="folder-path-input"
|
||
placeholder="Output für Umbenennung" readonly>
|
||
<button class="btn-secondary" onclick="app.selectWerksOutput()">
|
||
<i data-lucide="folder-open"></i>
|
||
Wählen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="watcher-controls">
|
||
<div class="watcher-status-display">
|
||
<span class="watcher-status-dot" id="werksWatcherDot"></span>
|
||
<span id="werksWatcherStatusText">Gestoppt</span>
|
||
</div>
|
||
<div class="watcher-buttons">
|
||
<button class="btn-primary btn-start" id="btnStartWerksWatcher"
|
||
onclick="app.startWerksWatcher()">
|
||
<i data-lucide="play"></i>
|
||
Starten
|
||
</button>
|
||
<button class="btn-secondary btn-pause" id="btnPauseWerksWatcher"
|
||
onclick="app.pauseWerksWatcher()" disabled>
|
||
<i data-lucide="pause"></i>
|
||
Pausieren
|
||
</button>
|
||
<button class="btn-secondary btn-resume" id="btnResumeWerksWatcher"
|
||
onclick="app.resumeWerksWatcher()" style="display:none">
|
||
<i data-lucide="play"></i>
|
||
Fortsetzen
|
||
</button>
|
||
<button class="btn-secondary btn-stop" id="btnStopWerksWatcher" onclick="app.stopWerksWatcher()"
|
||
disabled>
|
||
<i data-lucide="square"></i>
|
||
Stoppen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Customer Mappings -->
|
||
<div class="log-section" style="margin-top: 40px;">
|
||
<div class="preview-header">
|
||
<h2>
|
||
<i data-lucide="map"></i>
|
||
Kundennummern-Zuordnung
|
||
</h2>
|
||
</div>
|
||
<p class="subtitle" style="margin-bottom: 20px;">Weisen Sie Kundennummern automatisch einer
|
||
Konvertierung zu.</p>
|
||
|
||
<div class="mapping-editor">
|
||
<div class="folder-input-row" style="margin-bottom: 20px;">
|
||
<input type="text" id="newMappingId" class="folder-path-input"
|
||
placeholder="Kundennummer (z.B. 5060)" style="max-width: 200px;">
|
||
<select id="newMappingMode" class="folder-path-input" style="max-width: 250px;">
|
||
<option value="outbound-bosch">VDA 4913 → Bosch DESADV</option>
|
||
<option value="outbound-zf">VDA 4913 → ZF DESADV</option>
|
||
<option value="outbound-ifm">VDA 4913 → IFM DELVRY03</option>
|
||
<option value="inbound-bosch">DELFOR → VDA 4905</option>
|
||
<option value="inbound-ifm">IFM DELFOR → VDA 4905</option>
|
||
<option value="inbound-invrpt">INVRPT → VDA 4913</option>
|
||
<option value="validate-edifact">EDIFACT Validieren</option>
|
||
</select>
|
||
<button class="btn-primary" onclick="app.addMapping()">
|
||
<i data-lucide="plus"></i>
|
||
Hinzufügen
|
||
</button>
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<table id="mappingTable">
|
||
<thead>
|
||
<tr>
|
||
<th>Kundennummer</th>
|
||
<th>Konvertierungs-Modus</th>
|
||
<th style="width: 100px;">Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<!-- Will be populated by JS -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Conversion Log -->
|
||
<div class="log-section">
|
||
<div class="preview-header">
|
||
<h2>Konvertierungs-Log</h2>
|
||
<button class="btn-secondary" onclick="app.clearLog()">
|
||
<i data-lucide="trash-2"></i>
|
||
Leeren
|
||
</button>
|
||
</div>
|
||
<div class="log-container" id="logContainer">
|
||
<div class="log-empty">Noch keine Aktivitäten.</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: VIEWER -->
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<main class="main-card page-content" id="pageViewer" style="display:none">
|
||
<div class="preview-header no-print">
|
||
<h2>EDI Dokument Viewer</h2>
|
||
<div class="viewer-actions">
|
||
<button class="btn-secondary" onclick="app.viewer.reset()" id="btnViewerBack" style="display:none">
|
||
<i data-lucide="arrow-left"></i>
|
||
Zurück
|
||
</button>
|
||
<button class="btn-primary" onclick="app.viewer.printDocument()" id="btnViewerPrint"
|
||
style="display:none">
|
||
<i data-lucide="printer"></i>
|
||
Als PDF speichern / Drucken
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="viewerDropZone" class="drop-zone no-print">
|
||
<i data-lucide="file-search"></i>
|
||
<h3>Datei hier ablegen oder klicken zur Anzeige</h3>
|
||
<p id="viewerDropText">Unterstützt DELFOR und VDA 4905/4913 Dateien</p>
|
||
<input type="file" id="viewerFileInput" class="hidden">
|
||
</div>
|
||
|
||
<!-- This container will hold the rendered HTML document -->
|
||
<div id="viewerDocumentRender" class="document-render-area">
|
||
<!-- Content injected by JS -->
|
||
</div>
|
||
</main>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: EDITOR -->
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<main class="main-card page-content" id="pageEditor" style="display:none">
|
||
<div class="preview-header no-print">
|
||
<h2>EDI Dokument Editor</h2>
|
||
<div class="viewer-actions">
|
||
<button class="btn-secondary" onclick="app.editor.reset()" id="btnEditorBack" style="display:none">
|
||
<i data-lucide="arrow-left"></i>
|
||
Zurück
|
||
</button>
|
||
<button class="btn-primary" onclick="app.editor.downloadDocument()" id="btnEditorDownload"
|
||
style="display:none">
|
||
<i data-lucide="download"></i>
|
||
Speichern / Download
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="editorDropZone" class="drop-zone no-print">
|
||
<i data-lucide="edit"></i>
|
||
<h3>EDI Datei hier ablegen oder klicken zur Bearbeitung</h3>
|
||
<p id="editorDropText">Unterstützt EDIFACT und VDA Dateien</p>
|
||
<input type="file" id="editorFileInput" class="hidden">
|
||
</div>
|
||
|
||
<!-- This container will hold the editable segments -->
|
||
<div id="editorDocumentRender" class="editor-render-area" style="display:none;">
|
||
<!-- Content injected by JS -->
|
||
</div>
|
||
</main>
|
||
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<!-- PAGE: HISTORY -->
|
||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||
<main class="main-card page-content" id="pageHistory" style="display:none">
|
||
<h2 class="settings-title">
|
||
<i data-lucide="database"></i>
|
||
Konvertierungs-Historie
|
||
</h2>
|
||
<p class="subtitle" style="margin-bottom: 20px;">Vollständige Nachverfolgung aller durchgeführten
|
||
Konvertierungen.</p>
|
||
|
||
<!-- Stats -->
|
||
<div class="stats-grid" id="historyStats">
|
||
<div class="stat-card">
|
||
<div class="stat-value">-</div>
|
||
<div class="stat-label">Gesamt</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">-</div>
|
||
<div class="stat-label">Erfolgreich</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">-</div>
|
||
<div class="stat-label">Fehlerhaft</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">-</div>
|
||
<div class="stat-label">Heute</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Filter Bar -->
|
||
<div class="history-filter-bar">
|
||
<div class="history-filter-buttons">
|
||
<button class="btn-secondary history-filter-btn active" data-filter="ALL"
|
||
onclick="app.historyManager.setFilter('ALL')">
|
||
Alle
|
||
</button>
|
||
<button class="btn-secondary history-filter-btn" data-filter="ERFOLGREICH"
|
||
onclick="app.historyManager.setFilter('ERFOLGREICH')">
|
||
✅ Erfolgreich
|
||
</button>
|
||
<button class="btn-secondary history-filter-btn" data-filter="FEHLERHAFT"
|
||
onclick="app.historyManager.setFilter('FEHLERHAFT')">
|
||
❌ Fehlerhaft
|
||
</button>
|
||
</div>
|
||
<div class="history-search-row">
|
||
<input type="text" id="historySearch" class="folder-path-input"
|
||
placeholder="🔍 Suche nach Dateiname, Kunden-ID..."
|
||
oninput="app.historyManager.onSearch(this.value)" style="max-width:350px;">
|
||
<button class="btn-secondary" onclick="app.historyManager.exportCSV()">
|
||
<i data-lucide="download" style="width:14px;height:14px;"></i> CSV Export
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Table -->
|
||
<div class="history-table-wrapper">
|
||
<table class="history-table">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:50px;">ID</th>
|
||
<th style="width:140px;">Zeitstempel</th>
|
||
<th>Dateiname</th>
|
||
<th style="width:180px;">Modus</th>
|
||
<th style="width:90px;">Status</th>
|
||
<th style="width:50px;"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="historyTableBody">
|
||
<tr>
|
||
<td colspan="6"
|
||
style="text-align:center; padding:40px; color: var(--text-dim); font-style:italic;">Lade
|
||
Daten...</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Pagination -->
|
||
<div class="history-pagination" id="historyPagination"></div>
|
||
</main>
|
||
|
||
<!-- History Detail Modal -->
|
||
<div id="historyDetailModal" class="history-detail-modal" style="display:none;">
|
||
<div class="history-detail-modal-content">
|
||
<div id="historyDetailContent"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SCRIPTS -->
|
||
<script src="js/vda-parser.js"></script>
|
||
<script src="js/edifact-logic.js"></script>
|
||
<script src="js/config-parser.js"></script>
|
||
<script src="js/vda4913-to-desadv.js"></script>
|
||
<script src="js/vda4913-to-desadv-zf.js"></script>
|
||
<script src="js/vda4913-to-delvry03.js"></script>
|
||
<script src="js/delfor-parser.js"></script>
|
||
<script src="js/vda4905-generator.js"></script>
|
||
<script src="js/ifm_delfor-vda4905.js"></script>
|
||
<script src="js/invrpt-to-vda4913.js"></script>
|
||
<script src="js/watcher-bridge.js"></script>
|
||
<script src="js/outbound-watcher-bridge.js"></script>
|
||
<script src="js/werks-watcher-bridge.js"></script>
|
||
<script src="js/viewer.js"></script>
|
||
<script src="js/editor.js"></script>
|
||
<script src="js/history.js"></script>
|
||
<script src="js/app.js"></script>
|
||
|
||
<script>
|
||
// Init App safely
|
||
try {
|
||
window.app = new window.EDIBridge.App();
|
||
if (window.lucide) {
|
||
try { lucide.createIcons(); } catch (e) { console.warn("Lucide Error", e); }
|
||
}
|
||
} catch (e) {
|
||
console.error("App Fatal Error:", e);
|
||
alert("App Fatal Error: " + e.message);
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |