Änderungen in der Suche

This commit is contained in:
2026-03-11 17:24:14 +01:00
parent 58325e8583
commit dcfadb51d3
5 changed files with 136 additions and 25 deletions

View File

@@ -15,7 +15,7 @@
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
background: #0066FF;
min-height: 100vh;
padding: 20px;
}
@@ -70,6 +70,21 @@
border-color: #667eea;
}
.search-filter {
padding: 15px 12px;
font-size: 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
background: white;
color: #333;
cursor: pointer;
min-width: 140px;
}
.search-filter:focus {
outline: none;
border-color: #667eea;
}
.search-button {
padding: 15px 40px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -198,6 +213,15 @@
.record-field {
display: flex;
padding: 5px 0;
margin: 0 -15px;
padding-left: 15px;
padding-right: 15px;
}
.record-body .record-field:nth-child(even) {
background: rgba(0,0,0,0.04);
}
.record-body .record-field:nth-child(odd) {
background: transparent;
}
.field-name {
@@ -209,6 +233,16 @@
.field-value {
color: #333;
word-break: break-word;
white-space: pre-line;
}
.field-value .part-link {
color: #1565c0;
text-decoration: none;
font-weight: 600;
}
.field-value .part-link:hover {
text-decoration: underline;
}
.highlight {
@@ -301,6 +335,12 @@
placeholder="Suchbegriff eingeben..."
autofocus
>
<select id="statusFilter" class="search-filter" title="Status-Filter">
<option value="">Alle</option>
<option value="aktiv">Nur Aktiv</option>
<option value="pruefbar">Nur Prüfbar</option>
<option value="inaktiv">Nur Inaktiv</option>
</select>
<button id="searchButton" class="search-button">Suchen</button>
<button id="configButton" class="config-button" style="display: none;">Konfiguration</button>
</div>
@@ -310,10 +350,6 @@
<div class="stat-value" id="totalMatches">0</div>
<div class="stat-label">Treffer</div>
</div>
<div class="stat-item">
<div class="stat-value" id="tablesSearched">0</div>
<div class="stat-label">Tabellen durchsucht</div>
</div>
<div class="stat-item">
<div class="stat-value" id="searchTime">0ms</div>
<div class="stat-label">Suchzeit</div>
@@ -329,6 +365,7 @@
const searchButton = document.getElementById('searchButton');
const resultsDiv = document.getElementById('results');
const statsDiv = document.getElementById('stats');
const statusFilterSelect = document.getElementById('statusFilter');
let currentSearchTerm = '';
// Enter-Taste zum Suchen
@@ -340,6 +377,19 @@
searchButton.addEventListener('click', performSearch);
resultsDiv.addEventListener('click', (e) => {
const link = e.target.closest('.part-link');
if (!link) return;
e.preventDefault();
const part = link.getAttribute('data-part');
if (part) {
searchInput.value = part;
// Beim Klick auf "Ersetzt durch" immer auf "Alle" setzen
statusFilterSelect.value = '';
performSearch();
}
});
async function performSearch() {
const searchTerm = searchInput.value.trim();
@@ -357,7 +407,11 @@
const startTime = performance.now();
try {
const response = await fetch(`/api/search?q=${encodeURIComponent(searchTerm)}`);
const statusFilter = statusFilterSelect.value;
const url = new URL('/api/search', window.location.origin);
url.searchParams.set('q', searchTerm);
if (statusFilter) url.searchParams.set('status', statusFilter);
const response = await fetch(url.toString());
const data = await response.json();
const endTime = performance.now();
@@ -380,7 +434,6 @@
// Statistiken anzeigen
statsDiv.style.display = 'flex';
document.getElementById('totalMatches').textContent = data.totalMatches;
document.getElementById('tablesSearched').textContent = data.tablesSearched;
document.getElementById('searchTime').textContent = searchTime + 'ms';
// Ergebnisse anzeigen
@@ -405,7 +458,7 @@
<span class="table-count">${tableResult.matchCount} Treffer</span>
</div>
<div class="records">
${tableResult.records.map(record => renderRecord(record)).join('')}
${tableResult.records.slice().sort((a, b) => getStatusSortOrder(a.Stat) - getStatusSortOrder(b.Stat)).map(record => renderRecord(record)).join('')}
</div>
</div>
`;
@@ -420,8 +473,8 @@
{ key: 'Teil', label: 'Teilenummer' },
{ key: 'Bez', label: 'Bezeichnung' },
{ key: 'Bez2', label: 'Bezeichnung 2' },
{ key: 'Ben7', label: 'Englischer Text' },
{ key: 'Ben8', label: 'Deutscher Text' },
{ key: 'Ben8', label: 'Bezeichnung 3' },
{ key: 'Ben7', label: 'Eng 3' },
{ key: 'Hersteller', label: 'Hersteller' },
{ key: 'Text', label: 'Zusatztext' },
{ key: 'PrsVK', label: 'Verkaufspreis in €' },
@@ -437,6 +490,14 @@
return 'record--aktiv'; // "" oder leer = aktiv
}
/** Sortierreihenfolge: 0 = aktiv (zuerst), 1 = prüfbar, 2 = Rest */
function getStatusSortOrder(stat) {
const s = (stat == null ? '' : String(stat).trim());
if (s === '') return 0; // aktiv
if (s === 'L') return 1; // prüfbar
return 2; // inaktiv, löschbar, pseudoteil
}
function getStatusLabel(stat) {
const s = (stat == null ? '' : String(stat).trim());
if (s === 'i') return 'Inaktiv';
@@ -458,7 +519,20 @@
for (const { key, label } of DISPLAY_COLUMNS) {
if (!(key in record)) continue;
const value = record[key];
const displayValue = value === null || value === undefined ? '' : highlightSearchTerm(String(value));
let displayValue;
if (key === 'Ersatz' && value != null && String(value).trim() !== '') {
const partNum = String(value).trim();
const safePart = escapeHtml(partNum);
const safePartAttr = safePart.replace(/"/g, '&quot;');
displayValue = `<a href="#" class="part-link" data-part="${safePartAttr}">${safePart}</a>`;
} else if (key === 'PrsVK') {
const isVkTeil = record.VkTeil != null && Number(record.VkTeil) !== 0;
displayValue = isVkTeil && value != null && String(value).trim() !== ''
? highlightSearchTerm(String(value))
: escapeHtml('kein Verkaufsteil');
} else {
displayValue = value === null || value === undefined ? '' : highlightSearchTerm(String(value));
}
html += `
<div class="record-field">
<span class="field-name">${escapeHtml(label)}:</span>