Files
shop-old/tba-search.php.bak_20260730_toggle

1222 lines
62 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Krempl PostgreSQL Search Test Interface
* Search for devices and show matching ersatzteile
*/
require_once __DIR__ . '/core/postgres/KremplDB.php';
$search_term = isset($_GET['q']) ? trim($_GET['q']) : '';
$results = [];
$item_results = [];
$search_time = 0;
$item_search_time = 0;
$error_message = '';
// "Nur verfuegbare Shop-Artikel" ist jetzt der IST-Zustand (Default AN): das verkleinert die
// Trefferliste auf real bestellbare Teile, und getAvailableItemsForGeraet() liefert dabei
// items.id mit -- also sind die Chips direkt in den Shop verlinkbar. Abschaltbar mit
// ?shop_items=0 (die Checkbox sendet das ueber ein vorgeschaltetes hidden-Feld).
$show_shop_items = !isset($_GET['shop_items']) || $_GET['shop_items'] !== '0';
$v2_guided = false; // gefuehrte Ansicht aktiv (ein klarer Top-Treffer)
$v2_top_detail = null; // Volldaten des Top-Geraets aus geraete
$v2_brandpick = []; // marke => anzahl, wenn erst der Hersteller geklaert werden muss
$v2_marke = isset($_GET['marke']) ? trim($_GET['marke']) : ''; // gewaehlter Hersteller
$v2_variants = []; // BSH-Bauzustaende /01 /02 ..., wenn nur der Zeitraum unterscheidet
$v2_variant_base = ''; // gemeinsame Typnummer ohne Suffix, z.B. "WT46W560BY"
try {
// MySQL wird in beiden Fällen gebraucht (rechte Spalte = Artikel-Suche)
$db = new KremplDB(true);
if ($search_term !== '') {
// Links: Geräte-Suche (PostgreSQL)
$start_time = microtime(true);
$results = $db->searchGeraete($search_term, 20);
if ($show_shop_items) {
foreach ($results as &$device) {
$device['shop_items'] = $db->getAvailableItemsForGeraet($device['geraet_id'], 200);
}
unset($device);
}
$search_time = (microtime(true) - $start_time) * 1000;
// Rechts: Artikel-/Ersatzteil-Suche (MySQL)
$start_time2 = microtime(true);
$item_results = $db->searchItems($search_term, 20);
$item_search_time = (microtime(true) - $start_time2) * 1000;
// --- Hersteller-Filter (kommt aus der Hersteller-Rueckfrage) ---
if ($v2_marke !== '') {
$results = array_values(array_filter($results, function ($d) use ($v2_marke) {
return isset($d['marke']) && trim($d['marke']) === $v2_marke;
}));
}
// --- Stufe 1: muss erst der Hersteller geklaert werden? ---
// Dasselbe Modell laeuft oft unter mehreren Konzern-/Versandhausmarken. Dann haben
// alle Top-Treffer denselben Score und denselben Modellnamen -- eine Bestaetigung
// waere geraten. Der Hersteller steht dem Kunden aber auf dem Typenschild zur
// Verfuegung, also fragen wir zuerst danach. Beispiel MUFF21VLQS: 10x Score 100
// ueber AEG, Electrolux, Frigidaire, Gibson.
if (count($results) > 1) {
$top_score = (int)$results[0]['score'];
$topgroup = array_filter($results, function ($d) use ($top_score) {
return (int)$d['score'] === $top_score;
});
$brands = [];
$models = [];
foreach ($topgroup as $d) {
$m = trim($d['marke'] ?? '');
if ($m !== '') { $brands[$m] = ($brands[$m] ?? 0) + 1; }
$models[mb_strtolower(trim($d['modell_bezeichnung'] ?? ''))] = true;
}
// Nur fragen, wenn es wirklich EIN Modell bei MEHREREN Marken ist.
if (count($brands) > 1 && count($models) === 1) {
arsort($brands);
$v2_brandpick = $brands;
}
// --- Stufe 1b: Varianten-Auswahl (BSH-Bauzustaende) ---
// SIEMENS/BOSCH haengen "/01", "/02" ... an die Typnummer in nr. Laesst der Kunde
// das Suffix weg ("WT46W560BY"), kommen alle Bauzustaende mit gleichem Score
// zurueck und unterscheiden sich NUR im Produktionszeitraum. Dann fragen wir
// danach, statt zehn optisch identische Zeilen zu zeigen.
if (!$v2_brandpick) {
$basis = [];
foreach ($topgroup as $d) {
$n = trim($d['nr'] ?? '');
$basis[($p = strpos($n, '/')) !== false ? substr($n, 0, $p) : $n] = true;
}
if (count($basis) === 1 && count($topgroup) > 1 && count($brands) <= 1) {
$v2_variant_base = (string)array_key_first($basis);
// Nur wenn die Treffer wirklich Suffix-Varianten sind, nicht zufaellig
// gleichnamige Geraete: mindestens einer muss ein "/" tragen.
$has_suffix = false;
foreach ($topgroup as $d) { if (strpos((string)($d['nr'] ?? ''), '/') !== false) { $has_suffix = true; break; } }
if ($has_suffix) {
$det_batch = $db->getGeraetDetailsBatch(array_column($topgroup, 'geraet_id'));
foreach ($topgroup as $d) {
$det = $det_batch[$d['geraet_id']] ?? [];
$v2_variants[] = [
'nr' => (string)($d['nr'] ?? ''),
'id' => $d['geraet_id'],
'von' => $det['produktionsstart'] ?? '',
'bis' => $det['produktionsende'] ?? '',
'typ_de'=> $det['typ_de'] ?? '',
'marke' => $d['marke'] ?? '',
];
}
usort($v2_variants, function ($a, $b) { return strcmp($a['nr'], $b['nr']); });
}
}
}
}
// --- Stufe 2: gibt es EINEN klaren Top-Treffer? ---
// Nur dann darf man "Das ist dein Geraet" behaupten. Bedingung: Top-Score >= 95
// UND mindestens 10 Punkte Abstand zum Zweiten. Beispiel "Lavatherm 400": 100 vs. 75.
// Entfaellt, solange die Hersteller-Frage offen ist.
if (!$v2_brandpick && !$v2_variants && count($results) > 0) {
$v2_top_score_raw = (int)$results[0]['score'];
$v2_second_raw = isset($results[1]) ? (int)$results[1]['score'] : 0;
if ($v2_top_score_raw >= 95 && ($v2_top_score_raw - $v2_second_raw) >= 10) {
$v2_guided = true;
$v2_top_detail = $db->getGeraetDetails($results[0]['geraet_id']);
}
}
// --- Shop-Links fuer die Ersatzteil-Chips ---
// Die Chips kommen aus PostgreSQL und kennen nur navision_id. Damit sie -- wie die
// Artikel weiter unten -- in den Shop verlinken, wird einmalig gesammelt aufgeloest.
// Nur die tatsaechlich gerenderten (max. 10 je Geraet), sonst waeren es Tausende.
if ($results) {
$nav_ids = [];
foreach ($results as $d) {
foreach (array_slice($d['ersatzteile'] ?? [], 0, 10) as $p) {
if (!empty($p['navision_id'])) { $nav_ids[] = $p['navision_id']; }
}
}
if ($nav_ids) { $v2_shopmap = $db->getShopItemsByNavisionIds($nav_ids); }
}
}
} catch (Exception $e) {
$error_message = $e->getMessage();
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Krempl PostgreSQL Search Test</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: #f5f5f5;
padding: 20px;
}
.container {
max-width: 1600px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.split-results {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-top: 20px;
}
.split-results > div {
min-width: 0;
}
.split-results h2 {
font-size: 16px;
color: #444;
background: #f4f4f4;
padding: 10px 14px;
border-left: 4px solid #4CAF50;
margin-bottom: 14px;
}
.split-results .right-pane h2 {
border-left-color: #1976D2;
}
.item-card {
border: 1px solid #e0e0e0;
border-radius: 4px;
margin-bottom: 8px;
padding: 10px 12px;
background: #fafafa;
font-size: 13px;
}
.item-card .item-name {
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.item-card .item-meta {
color: #666;
font-size: 12px;
}
.item-card .item-meta strong {color:#1976D2;}
.inventory-positive {color:#2e7d32;font-weight:bold;}
.inventory-zero {color:#aaa;}
.inventory-null {color:#aaa;font-style:italic;}
@media (max-width: 900px) {
.split-results { grid-template-columns: 1fr; }
}
h1 {
color: #333;
margin-bottom: 20px;
}
.search-box {
margin-bottom: 30px;
}
.search-input {
width: 100%;
padding: 12px 15px;
font-size: 16px;
border: 2px solid #ddd;
border-radius: 4px;
transition: border-color 0.3s;
}
.search-input:focus {
outline: none;
border-color: #4CAF50;
}
.search-btn {
padding: 10px 20px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
transition: background 0.3s;
white-space: nowrap;
}
.search-btn:hover {
background: #45a049;
}
#shopItemsToggle {
cursor: pointer;
width: 18px;
height: 18px;
}
.search-info {
color: #666;
margin-bottom: 20px;
font-size: 14px;
}
.device-card {
border: 1px solid #e0e0e0;
border-radius: 4px;
margin-bottom: 20px;
background: #fafafa;
overflow: hidden;
}
.device-card.collapsed .ersatzteile-section {
display: none;
}
.device-header {
display: flex;
justify-content: space-between;
align-items: start;
padding: 15px;
margin-bottom: 0;
border-bottom: 2px solid #e0e0e0;
}
.score-badge {
cursor: pointer;
transition: all 0.2s;
user-select: none;
}
.score-badge:hover {
opacity: 0.9;
transform: scale(1.02);
}
.toggle-arrow {
display: inline-block;
margin-left: 8px;
transition: transform 0.3s;
font-size: 10px;
}
.device-card.collapsed .toggle-arrow {
transform: rotate(-90deg);
}
.device-info {
flex: 1;
}
.device-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 5px;
}
.device-title a {
color: #333;
text-decoration: none;
transition: color 0.2s;
}
.device-title a:hover {
color: #4CAF50;
text-decoration: underline;
}
.device-details {
color: #666;
font-size: 14px;
}
.device-details span {
display: inline-block;
margin-right: 15px;
}
.score-badge {
display: inline-block;
padding: 5px 12px;
border-radius: 20px;
font-weight: bold;
font-size: 14px;
}
.score-100 { background: #4CAF50; color: white; }
.score-95 { background: #66BB6A; color: white; }
.score-90 { background: #81C784; color: white; }
.score-80 { background: #FFC107; color: white; }
.score-75 { background: #FFD54F; color: #333; }
.score-60 { background: #FFE082; color: #333; }
.score-default { background: #BDBDBD; color: white; }
.ersatzteile-section {
padding: 15px;
}
.ersatzteile-title {
font-weight: bold;
color: #333;
margin-bottom: 10px;
margin-top: 10px;
font-size: 14px;
}
.ersatzteile-table {
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 4px;
overflow: hidden;
}
.ersatzteile-table th {
background: #f0f0f0;
padding: 8px;
text-align: left;
font-size: 13px;
font-weight: 600;
color: #555;
}
.ersatzteile-table td {
padding: 8px;
border-top: 1px solid #e0e0e0;
font-size: 13px;
}
.ersatzteile-table tr:hover {
background: #f9f9f9;
}
.navision-id {
font-weight: bold;
color: #1976D2;
}
.no-results {
text-align: center;
padding: 40px;
color: #999;
}
.match-type {
display: inline-block;
font-size: 11px;
padding: 2px 6px;
background: #e0e0e0;
border-radius: 3px;
color: #666;
margin-left: 8px;
}
.error-message {
background: #ffebee;
border: 1px solid #ef5350;
color: #c62828;
padding: 15px;
border-radius: 4px;
margin-bottom: 20px;
}
.error-message strong {
display: block;
margin-bottom: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>Krempl PostgreSQL Search Test</h1>
<div class="search-box">
<form method="GET" action="" id="searchForm">
<input
type="text"
name="q"
class="search-input"
placeholder="Gerätesuche (z.B. AWB 921 PH, ZCS 2100B, 2100B)"
value="<?php echo htmlspecialchars($search_term); ?>"
autofocus
/>
<div style="margin-top: 10px; display: flex; align-items: center; gap: 15px;">
<button type="submit" class="search-btn">Suchen</button>
<label style="font-size: 14px; cursor: pointer; display: flex; align-items: center; gap: 5px;">
<?php // hidden vor der Checkbox: unchecked sendet sonst gar nichts, und
// der Default ist jetzt AN -- ohne das liesse sich nie abschalten. ?>
<input type="hidden" name="shop_items" value="0">
<input type="checkbox" name="shop_items" value="1" <?php echo $show_shop_items ? 'checked' : ''; ?> id="shopItemsToggle" onchange="document.getElementById('searchForm').submit();">
<span>Nur verfügbare Shop-Artikel (MySQL)</span>
</label>
</div>
</form>
</div>
<?php if ($error_message): ?>
<div class="error-message">
<strong>Fehler bei der Datenbankverbindung:</strong>
<?php echo htmlspecialchars($error_message); ?>
</div>
<?php endif; ?>
<?php if ($search_term !== '' && !$error_message): ?>
<div class="split-results">
<!-- LINKS: Geräte-Suche (PostgreSQL) -->
<div class="left-pane">
<h2>Geräte (PostgreSQL)
— <?php echo count($results); ?> Treffer
(<?php echo number_format($search_time, 0); ?>&thinsp;ms)
</h2>
<?php if (count($results) === 0): ?>
<div class="no-results" style="padding:20px;">
Keine Geräte gefunden.
</div>
<?php endif; ?>
<?php foreach ($results as $device): ?>
<?php
$score = (int)$device['score'];
$score_class = 'score-default';
if ($score >= 100) $score_class = 'score-100';
elseif ($score >= 95) $score_class = 'score-95';
elseif ($score >= 90) $score_class = 'score-90';
elseif ($score >= 80) $score_class = 'score-80';
elseif ($score >= 75) $score_class = 'score-75';
elseif ($score >= 60) $score_class = 'score-60';
?>
<div class="device-card collapsed" id="device-<?php echo $device['geraet_id']; ?>">
<div class="device-header">
<div class="device-info">
<div class="device-title">
<a href="geraet.php?id=<?php echo $device['geraet_id']; ?>&q=<?php echo urlencode($search_term); ?><?php echo $show_shop_items ? '&shop_items=1' : ''; ?>" style="color: #333; text-decoration: none;">
<?php echo htmlspecialchars($device['modell_bezeichnung']); ?>
</a>
<span class="match-type"><?php echo htmlspecialchars($device['match_type']); ?></span>
</div>
<div class="device-details">
<span><strong>Marke:</strong> <?php echo htmlspecialchars($device['marke']); ?></span>
<span><strong>Typ:</strong> <?php echo htmlspecialchars($device['typ']); ?></span>
<span><strong>Nr:</strong> <?php echo htmlspecialchars($device['nr']); ?></span>
<span><strong>ID:</strong> <?php echo htmlspecialchars($device['geraet_id']); ?></span>
</div>
</div>
<div>
<span class="score-badge <?php echo $score_class; ?>" onclick="toggleDevice(<?php echo $device['geraet_id']; ?>)">
Score: <?php echo $score; ?>
<span class="toggle-arrow">▼</span>
</span>
</div>
</div>
<?php if ($show_shop_items && isset($device['shop_items'])): ?>
<!-- Show available shop items -->
<?php if (count($device['shop_items']) > 0): ?>
<div class="ersatzteile-section">
<div class="ersatzteile-title">
Verfügbare Shop-Artikel:
<span style="background: #4CAF50; color: white; padding: 3px 10px; border-radius: 12px; font-weight: bold; margin-left: 5px;">
<?php echo count($device['shop_items']); ?> verfügbar
</span>
</div>
<table class="ersatzteile-table">
<thead>
<tr>
<th>Artikel-Nr</th>
<th>Artikelname</th>
<th>Navision-ID</th>
<th>Lagerbestand</th>
</tr>
</thead>
<tbody>
<?php foreach ($device['shop_items'] as $item): ?>
<tr>
<td><?php echo htmlspecialchars($item['number']); ?></td>
<td><?php echo htmlspecialchars($item['name']); ?></td>
<td class="navision-id"><?php echo htmlspecialchars($item['matched_navision_id']); ?></td>
<td><?php echo (int)$item['inventory']; ?> Stück</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="ersatzteile-section">
<div class="ersatzteile-title" style="color: #999;">
Keine verfügbaren Shop-Artikel gefunden
</div>
</div>
<?php endif; ?>
<?php else: ?>
<!-- Show all Krempl ersatzteile -->
<?php if (count($device['ersatzteile']) > 0): ?>
<div class="ersatzteile-section">
<div class="ersatzteile-title">
Passende Ersatzteile (Krempl):
<span style="background: #2196F3; color: white; padding: 3px 10px; border-radius: 12px; font-weight: bold; margin-left: 5px;">
<?php echo count($device['ersatzteile']); ?> gesamt
</span>
</div>
<table class="ersatzteile-table">
<thead>
<tr>
<th>Navision ID</th>
<th>Krempl ID</th>
<th>Originalnummer</th>
<th>Marke</th>
</tr>
</thead>
<tbody>
<?php foreach ($device['ersatzteile'] as $ers): ?>
<tr>
<td class="navision-id"><?php echo htmlspecialchars($ers['navision_id']); ?></td>
<td><?php echo htmlspecialchars($ers['krempl_id']); ?></td>
<td><?php echo htmlspecialchars($ers['originalnummer']); ?></td>
<td><?php echo htmlspecialchars($ers['marke']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="ersatzteile-section">
<div class="ersatzteile-title" style="color: #999;">
Keine Ersatzteile gefunden
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div><!-- /left-pane -->
<!-- RECHTS: Artikel-/Ersatzteil-Suche (MySQL) -->
<div class="right-pane">
<h2>Ersatzteile / Artikel (MySQL items)
— <?php echo count($item_results); ?> Treffer
(<?php echo number_format($item_search_time, 0); ?>&thinsp;ms)
</h2>
<?php if (count($item_results) === 0): ?>
<div class="no-results" style="padding:20px;">
Keine Artikel gefunden.
</div>
<?php else: ?>
<?php foreach ($item_results as $item): ?>
<div class="item-card">
<div class="item-name"><?= htmlspecialchars($item['name']) ?></div>
<div class="item-meta">
Art-Nr: <strong><?= htmlspecialchars($item['number']) ?></strong>
· Navision: <strong><?= htmlspecialchars($item['matched_navision_id']) ?></strong>
· Lager:
<?php
$inv = $item['inventory'];
if ($inv === null) {
echo '<span class="inventory-null">k.A.</span>';
} elseif ((int)$inv > 0) {
echo '<span class="inventory-positive">' . (int)$inv . ' Stk</span>';
} else {
echo '<span class="inventory-zero">0</span>';
}
?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div><!-- /right-pane -->
</div><!-- /split-results -->
<?php
// ==================================================================
// A/B – NEUE DARSTELLUNG (Prototyp, geführte Ergebnis-Ansicht)
// Nutzt dieselben Daten ($results / $item_results), nur menschlich.
// ==================================================================
if (!function_exists('v2_confidence')) {
/**
* Anzeigename eines Geraets. modell_bezeichnung ist bei 490.522 von 1.675.828
* Geraeten LEER (29%) -- vor allem bei BSH (SIEMENS/BOSCH), wo die Typnummer
* stattdessen in nr steht (z.B. "WT46W560BY/01"). Ohne Fallback rendern die
* Kacheln komplett namenlos.
*/
function v2_gname($d) {
foreach (['modell_bezeichnung', 'bezeichnung_original', 'nr'] as $k) {
if (isset($d[$k]) && trim((string)$d[$k]) !== '') return trim($d[$k]);
}
return '(ohne Bezeichnung)';
}
/**
* Produktionsdatum -> Jahr. In produktionsstart/-ende stecken ZWEI Formate:
* YYYYMMDD z.B. "19790101" (AEG Lavatherm 400)
* YYMM z.B. "8810" (SIEMENS WT46W560BY/01 = Oktober 1988)
* Bei YYMM gilt: >= 70 -> 19YY, sonst 20YY.
*/
function v2_jahr4($v) {
$s = preg_replace('/\D/', '', (string)$v);
if ($s === '') return '';
if (strlen($s) >= 6) return substr($s, 0, 4); // YYYYMM(DD)
if (strlen($s) === 4) { // YYMM
$yy = (int)substr($s, 0, 2);
return (string)($yy >= 70 ? 1900 + $yy : 2000 + $yy);
}
if (strlen($s) === 2) { // nur YY
$yy = (int)$s;
return (string)($yy >= 70 ? 1900 + $yy : 2000 + $yy);
}
return '';
}
/** Monat/Jahr fuer die Variantenliste, z.B. "10/1988". Leer, wenn nicht ableitbar. */
function v2_monat($v) {
$s = preg_replace('/\D/', '', (string)$v);
$j = v2_jahr4($s);
if ($j === '') return '';
if (strlen($s) >= 6) $m = substr($s, 4, 2); // YYYYMM(DD)
elseif (strlen($s) === 4) $m = substr($s, 2, 2); // YYMM
else return $j;
$m = (int)$m;
return ($m >= 1 && $m <= 12) ? sprintf('%02d/%s', $m, $j) : $j;
}
function v2_confidence($score) {
$s = (int)$score;
if ($s >= 100) return ['Exakter Treffer', '#2e7d32', '#e8f5e9', '✓'];
if ($s >= 90) return ['Sehr wahrscheinlich dein Gerät','#388e3c', '#edf7ee', '✓'];
if ($s >= 75) return ['Könnte passen', '#f9a825', '#fff8e1', '≈'];
return ['Ähnlich – bitte prüfen', '#9e9e9e', '#f5f5f5', '?'];
}
// nml/Nachfolger steckt im Artikelnamen: "(nml)"/"(nmle)" + "Nachfolger <Nr>"
function v2_nml_info($name) {
$is_nml = (bool)preg_match('/\(nml[e]?\)/i', $name);
$nachf = null;
// Nachfolger-Nummer muss mind. eine Ziffer enthalten (schließt "Nachfolger Original" aus)
if (preg_match('/Nachfolger\s+([A-Za-z0-9\-\/\.]*\d[A-Za-z0-9\-\/\.]*)/i', $name, $m)) {
$nachf = $m[1];
}
$kein_ersatz = (stripos($name, 'kein Ersatz') !== false);
// Anzeigename säubern: (nml)-Marker + "Nachfolger ... Original(teil)" raus
$clean = preg_replace('/\s*\(nml[e]?\)\s*/i', ' ', $name);
$clean = preg_replace('/\s*Nachfolger\s+[A-Za-z0-9\-\/\.]*\d[A-Za-z0-9\-\/\.]*\s*/i', ' ', $clean);
$clean = preg_replace('/\s*(Originalteil|Original)\s*$/i', '', $clean);
$clean = trim(preg_replace('/\s{2,}/', ' ', $clean));
return ['is_nml'=>$is_nml, 'nachfolger'=>$nachf, 'kein_ersatz'=>$kein_ersatz, 'clean'=>($clean ?: $name)];
}
}
// Treffer in "stark" (>=75) und "schwach" (<75) teilen
$v2_strong = []; $v2_weak = [];
foreach ($results as $d) { ((int)$d['score'] >= 75) ? $v2_strong[] = $d : $v2_weak[] = $d; }
// Artikel klassifizieren: kaufbar / ausgelaufen-mit-Nachfolger / tot
$g_buy = []; $g_succ = []; $g_dead = [];
foreach ($item_results as $it) {
$it['_nml'] = v2_nml_info($it['name']);
if (!$it['_nml']['is_nml']) $g_buy[] = $it; // regulär
elseif ($it['_nml']['nachfolger']) $g_succ[] = $it; // ausgelaufen, Nachfolger da
else $g_dead[] = $it; // ausgelaufen, kein Ersatz
}
$v2_top_score = isset($results[0]) ? (int)$results[0]['score'] : 0;
// Intent-Einordnung
if ($v2_top_score >= 90) $v2_headline = 'Wir haben dein Gerät gefunden.';
elseif (count($v2_strong) > 0) $v2_headline = 'Das könnte dein Gerät sein:';
elseif (count($item_results)) $v2_headline = 'Passende Artikel gefunden:';
else $v2_headline = 'Mehrere mögliche Treffer – grenz gern ein.';
?>
<hr style="margin:40px 0 0; border:none; border-top:3px dashed #cfcfcf;">
<style>
.v2{margin-top:24px;font-size:15px}
.v2 .v2-flag{display:inline-block;background:#111;color:#fff;font-size:11px;font-weight:700;
letter-spacing:.5px;padding:3px 10px;border-radius:4px;text-transform:uppercase}
.v2 .v2-head{font-size:22px;font-weight:700;color:#222;margin:14px 0 4px}
.v2 .v2-sub{color:#777;font-size:13px;margin-bottom:22px}
.v2-dev{border:1px solid #e3e3e3;border-radius:10px;margin-bottom:16px;overflow:hidden;
box-shadow:0 1px 3px rgba(0,0,0,.05)}
.v2-dev-top{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;
padding:16px 18px;background:#fff}
.v2-dev-name{font-size:18px;font-weight:700;color:#1a1a1a;line-height:1.3}
.v2-dev-meta{color:#666;font-size:13px;margin-top:5px}
.v2-dev-meta b{color:#444}
.v2-conf{white-space:nowrap;font-size:12px;font-weight:700;padding:6px 12px;border-radius:20px}
.v2-parts{padding:14px 18px;border-top:1px solid #f0f0f0;background:#fcfcfc}
.v2-parts h4{font-size:13px;color:#555;margin-bottom:9px;font-weight:600}
.v2-chip{display:inline-block;background:#fff;border:1px solid #e0e0e0;border-radius:16px;
padding:4px 11px;margin:0 5px 6px 0;font-size:12px;color:#444}
.v2-chip b{color:#1565c0}
.v2-buy{background:#e8f5e9;border-color:#c8e6c9}
.v2-more{margin:6px 0 22px}
.v2-more summary{cursor:pointer;color:#1565c0;font-size:14px;padding:8px 0}
.v2-shop{margin-top:30px}
.v2-shop h3{font-size:16px;color:#333;margin-bottom:12px;border-left:4px solid #1976D2;padding-left:10px}
.v2-item{display:flex;justify-content:space-between;align-items:center;gap:14px;
border:1px solid #eee;border-radius:8px;padding:12px 15px;margin-bottom:8px;background:#fff}
.v2-item-name{font-weight:600;color:#222}
.v2-item-meta{color:#888;font-size:12px;margin-top:3px}
.v2-stock{white-space:nowrap;font-size:13px;font-weight:700}
.v2-in{color:#2e7d32}.v2-out{color:#c62828}.v2-na{color:#aaa;font-style:italic;font-weight:400}
.v2-cart{background:#4CAF50;color:#fff;border:none;border-radius:6px;padding:8px 14px;
font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap}
.v2-cart:disabled{background:#ccc;cursor:not-allowed}
.v2-hint{background:#fffdf3;border:1px dashed #e6d9a8;border-radius:8px;padding:10px 14px;
font-size:12px;color:#8a7a3a;margin-top:20px}
/* --- Gefuehrte Bestaetigung: EIN klarer Top-Treffer --- */
.v2-cf{border:2px solid #2e7d32;border-radius:12px;padding:22px 24px;margin:4px 0 18px;
background:linear-gradient(180deg,#f4fbf4 0%,#fff 60%);box-shadow:0 2px 8px rgba(46,125,50,.08)}
.v2-cf-q{font-size:13px;font-weight:700;color:#2e7d32;text-transform:uppercase;letter-spacing:.6px}
.v2-cf-name{font-size:26px;font-weight:700;color:#1a1a1a;line-height:1.25;margin:8px 0 2px}
.v2-cf-marke{font-size:15px;color:#555;font-weight:600}
.v2-cf-facts{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0 4px}
.v2-cf-fact{background:#fff;border:1px solid #dfe8df;border-radius:8px;padding:8px 13px;font-size:13px;color:#33691e}
.v2-cf-fact b{color:#1b5e20;display:block;font-size:11px;text-transform:uppercase;
letter-spacing:.4px;color:#7a8f7a;font-weight:700;margin-bottom:2px}
.v2-cf-act{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin-top:20px;
padding-top:16px;border-top:1px solid #e4efe4}
.v2-cf-yes{background:#2e7d32;color:#fff;border:none;border-radius:8px;padding:12px 22px;
font-size:15px;font-weight:700;text-decoration:none;display:inline-block}
.v2-cf-no{color:#1565c0;font-size:14px;text-decoration:underline;cursor:pointer;background:none;border:none;padding:0}
.v2-alt{margin:0 0 22px}
.v2-alt>summary{cursor:pointer;color:#1565c0;font-size:14px;padding:10px 0;font-weight:600}
.v2-alt[open]>summary{margin-bottom:10px}
/* Hersteller-Buendelung innerhalb der Alternativen */
.v2-mgroup{font-size:13px;font-weight:700;color:#455a64;text-transform:uppercase;letter-spacing:.6px;
margin:18px 0 10px;padding-bottom:6px;border-bottom:2px solid #eceff1}
.v2-mgroup:first-of-type{margin-top:6px}
.v2-mgroup span{display:inline-block;background:#eceff1;color:#546e7a;border-radius:10px;
padding:1px 8px;font-size:11px;margin-left:6px;letter-spacing:0}
/* Stufe 1: Hersteller-Rueckfrage bei Multi-Marken-Modellen */
.v2-cf-brand{border-color:#1565c0;background:linear-gradient(180deg,#f2f7fd 0%,#fff 60%);
box-shadow:0 2px 8px rgba(21,101,192,.08)}
.v2-cf-brand .v2-cf-q{color:#1565c0}
.v2-brands{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0 4px}
.v2-brand{display:inline-flex;align-items:center;gap:8px;background:#fff;border:2px solid #cfe0f5;
border-radius:10px;padding:12px 18px;font-size:15px;font-weight:700;color:#0d47a1;
text-decoration:none;transition:border-color .12s,background .12s}
.v2-brand:hover{border-color:#1565c0;background:#f5faff}
.v2-brand span{background:#e3eefb;color:#1565c0;border-radius:10px;padding:1px 8px;
font-size:12px;font-weight:600}
.v2-filter{background:#eef4fb;border:1px solid #cfe0f5;border-radius:8px;padding:9px 14px;
font-size:13px;color:#0d47a1;margin:0 0 16px;display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.v2-filter a{color:#1565c0}
/* Stufe 1b: BSH-Bauzustaende /01 /02 ... nur durch den Zeitraum unterscheidbar */
.v2-cf-var{border-color:#6a1b9a;background:linear-gradient(180deg,#f9f4fc 0%,#fff 60%);
box-shadow:0 2px 8px rgba(106,27,154,.08)}
.v2-cf-var .v2-cf-q{color:#6a1b9a}
.v2-vars{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px;margin-top:18px}
.v2-var{display:flex;align-items:center;gap:10px;background:#fff;border:2px solid #e6d9f0;
border-radius:10px;padding:11px 15px;text-decoration:none;transition:border-color .12s,background .12s}
.v2-var:hover{border-color:#6a1b9a;background:#fcf9fe}
.v2-var b{font-size:16px;font-weight:700;color:#4a148c;min-width:38px}
.v2-var span{font-size:13px;color:#666}
</style>
<div class="v2">
<span class="v2-flag">◇ Variante B – geführte Ansicht (Prototyp)</span>
<div class="v2-head"><?php echo htmlspecialchars($v2_headline); ?></div>
<div class="v2-sub">
<?php echo count($v2_strong); ?> passende Geräte
· <?php echo count($g_buy); ?> kaufbare Artikel
<?php if (count($g_succ)) echo ' · '.count($g_succ).' mit Nachfolger'; ?>
<?php if (count($g_dead)) echo ' · '.count($g_dead).' ausgelaufen'; ?>
<?php if (count($v2_weak)) echo ' · '.count($v2_weak).' weitere mögliche Geräte'; ?>
</div>
<?php
// Query-String-Bausteine fuer die Hersteller-Links
$v2_qs_shop = $show_shop_items ? '&amp;shop_items=1' : '';
$v2_qs_base = '?q=' . urlencode($search_term) . $v2_qs_shop;
?>
<?php if ($v2_marke !== ''): ?>
<div class="v2-filter">
<span>Hersteller: <b><?php echo htmlspecialchars($v2_marke); ?></b></span>
<a href="<?php echo $v2_qs_base; ?>">↺ alle Hersteller zeigen</a>
</div>
<?php endif; ?>
<?php if ($v2_brandpick): ?>
<div class="v2-cf v2-cf-brand">
<div class="v2-cf-q">Mehrere Hersteller führen dieses Modell</div>
<div class="v2-cf-name"><?php echo htmlspecialchars(v2_gname($results[0])); ?></div>
<div class="v2-cf-marke">Welcher Hersteller steht auf deinem Gerät?</div>
<div class="v2-brands">
<?php foreach ($v2_brandpick as $m => $n): ?>
<a class="v2-brand" href="<?php echo $v2_qs_base; ?>&amp;marke=<?php echo urlencode($m); ?>">
<?php echo htmlspecialchars($m); ?><span><?php echo (int)$n; ?></span>
</a>
<?php endforeach; ?>
</div>
<div style="font-size:12px;color:#78909c;margin-top:14px">
Der Hersteller steht meist auf dem Typenschild oder als Logo auf der Blende.
</div>
</div>
<?php endif; ?>
<?php if ($v2_variants): ?>
<div class="v2-cf v2-cf-var">
<div class="v2-cf-q">Dieses Modell gibt es in mehreren Bauzuständen</div>
<div class="v2-cf-name"><?php echo htmlspecialchars($v2_variant_base); ?></div>
<div class="v2-cf-marke">
<?php
$vm = trim($v2_variants[0]['marke'] ?? '');
$vt = trim($v2_variants[0]['typ_de'] ?? '');
echo htmlspecialchars(trim($vm.' '.$vt));
?>
· <?php echo count($v2_variants); ?> Varianten
</div>
<div class="v2-cf-marke" style="margin-top:14px;font-weight:400;color:#666">
Wann wurde dein Gerät gebaut? Die Nummer auf dem Typenschild endet auf
<b>/01</b>, <b>/02</b> … – wenn du sie findest, ist das der schnellste Weg.
</div>
<div class="v2-vars">
<?php foreach ($v2_variants as $v):
$von = v2_monat($v['von']); $bis = v2_monat($v['bis']);
if ($von && $bis && $von !== $bis) $zr = $von.' – '.$bis;
elseif ($von) $zr = 'ab '.$von;
elseif ($bis) $zr = 'bis '.$bis;
else $zr = 'Zeitraum unbekannt';
$suf = (($p = strpos($v['nr'], '/')) !== false) ? substr($v['nr'], $p) : '–';
?>
<a class="v2-var" href="?q=<?php echo urlencode($v['nr']); ?><?php echo $show_shop_items ? '&amp;shop_items=1' : ''; ?>">
<b><?php echo htmlspecialchars($suf); ?></b>
<span><?php echo htmlspecialchars($zr); ?></span>
</a>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
<?php if ($v2_guided && $v2_top_detail):
$det = $v2_top_detail;
// produktionsstart/-ende liegen als YYYYMMDD-String vor (z.B. "19790101")
$js = v2_jahr4($det['produktionsstart'] ?? '');
$je = v2_jahr4($det['produktionsende'] ?? '');
if ($js && $je && $js !== $je) $v2_zeit = $js.'–'.$je;
elseif ($js) $v2_zeit = 'ab '.$js;
elseif ($je) $v2_zeit = 'bis '.$je;
else $v2_zeit = '';
$v2_wg = array_filter([trim($det['wgtext1'] ?? ''), trim($det['wgtext2'] ?? '')]);
$v2_nparts = count($results[0]['ersatzteile'] ?? []);
?>
<div class="v2-cf">
<div class="v2-cf-q">Ist das dein Gerät?</div>
<div class="v2-cf-name"><?php echo htmlspecialchars(v2_gname($det)); ?></div>
<div class="v2-cf-marke"><?php echo htmlspecialchars($det['marke']); ?></div>
<div class="v2-cf-facts">
<?php if (!empty($det['typ_de'])): ?>
<div class="v2-cf-fact"><b>Gerätetyp</b><?php echo htmlspecialchars($det['typ_de']); ?></div>
<?php endif; ?>
<?php if ($v2_wg): ?>
<div class="v2-cf-fact"><b>Bauart</b><?php echo htmlspecialchars(implode(' · ', $v2_wg)); ?></div>
<?php endif; ?>
<?php if ($v2_zeit): ?>
<div class="v2-cf-fact"><b>Baujahr</b><?php echo htmlspecialchars($v2_zeit); ?></div>
<?php endif; ?>
</div>
<?php
// Ersatzteile des Top-Geraets direkt hier -- der alte v2-dev-Block fuer
// denselben Treffer entfaellt dadurch (war doppelt).
$v2_top_parts = $results[0]['ersatzteile'] ?? [];
$v2_top_buy = $results[0]['shop_items'] ?? null;
?>
<?php if ($v2_top_buy && count($v2_top_buy)): ?>
<div class="v2-parts" style="background:transparent;border-top:1px solid #e4efe4;margin-top:16px;padding:14px 0 0">
<h4>✓ Sofort erhältlich für dieses Gerät (<?php echo count($v2_top_buy); ?>):</h4>
<?php foreach (array_slice($v2_top_buy,0,8) as $b): ?>
<span class="v2-chip v2-buy"><b><?php echo htmlspecialchars($b['number']); ?></b>
· <?php echo htmlspecialchars(mb_strimwidth($b['name'],0,42,'…')); ?></span>
<?php endforeach; ?>
</div>
<?php elseif (count($v2_top_parts)): ?>
<div class="v2-parts" style="background:transparent;border-top:1px solid #e4efe4;margin-top:16px;padding:14px 0 0">
<h4><?php echo count($v2_top_parts); ?> passende Ersatzteile — Auswahl:</h4>
<?php foreach (array_slice($v2_top_parts,0,10) as $p): ?>
<span class="v2-chip"><b><?php echo htmlspecialchars($p['originalnummer']); ?></b>
<?php if (!empty($p['marke'])) echo '· '.htmlspecialchars($p['marke']); ?></span>
<?php endforeach; ?>
<?php if (count($v2_top_parts) > 10): ?>
<span class="v2-chip" style="border-style:dashed;color:#999;">+<?php echo count($v2_top_parts)-10; ?> weitere</span>
<?php endif; ?>
</div>
<?php endif; ?>
<div class="v2-cf-act">
<?php if (count($g_buy)): ?>
<a href="#v2-artikel" class="v2-cf-yes">Ja – Artikel im Shop zeigen (<?php echo count($g_buy); ?>)</a>
<?php endif; ?>
<?php $v2_alt_total = max(0, count($v2_strong) - 1) + count($v2_weak); ?>
<?php if ($v2_alt_total): ?>
<span style="color:#777;font-size:14px">Nicht mein Gerät?
<a href="#v2-alternativen" class="v2-cf-no">→ <?php echo $v2_alt_total; ?> weitere Treffer</a>
</span>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php
// Gefuehrter Modus: der Top-Treffer steckt komplett in der Bestaetigungskarte
// (inkl. Ersatzteile), erscheint hier also NICHT mehr -- sonst stand er doppelt.
// Alle weiteren Treffer (starke ab Index 1 + schwache) liegen hinter einem Klick
// und werden dort nach Hersteller gebuendelt: dasselbe Modell laeuft oft unter
// mehreren Konzern- bzw. Versandhausmarken (Lavatherm: AEG, Quelle, Neckermann,
// Asko, Electrolux, ...). Marken mit den meisten Treffern zuerst.
$v2_alt_open = false;
$v2_last_mgroup = null;
$v2_alt_total = 0;
$v2_list = $v2_strong;
$v2_mcount = [];
if ($v2_guided && $v2_top_detail) {
$v2_rest = array_merge(array_slice($v2_strong, 1), $v2_weak);
$v2_alt_total = count($v2_rest);
$by_marke = [];
foreach ($v2_rest as $d) {
$m = (isset($d['marke']) && trim($d['marke']) !== '') ? trim($d['marke']) : 'ohne Herstellerangabe';
$by_marke[$m][] = $d;
}
uasort($by_marke, function ($a, $b) { return count($b) <=> count($a); });
$v2_list = [];
foreach ($by_marke as $m => $ds) {
$v2_mcount[$m] = count($ds);
foreach ($ds as $d) { $d['_mgroup'] = $m; $v2_list[] = $d; }
}
}
?>
<?php foreach ($v2_list as $i => $d):
list($clabel,$ccol,$cbg,$cicon) = v2_confidence($d['score']);
$parts = $d['ersatzteile'] ?? [];
$buy = $d['shop_items'] ?? null; // nur wenn shop_items-Toggle an
if (!$v2_alt_open && ($v2_guided && $v2_top_detail)) {
echo '<details class="v2-alt" id="v2-alternativen"><summary>Nicht mein Gerät – '
. $v2_alt_total . ' weitere Treffer anzeigen</summary>';
$v2_alt_open = true;
}
// Bei der Varianten-Karte stehen dieselben Geraete schon als Buttons oben --
// die ausfuehrliche Liste (mit Ersatzteilen) deshalb ebenfalls einklappen.
if (!$v2_alt_open && $v2_variants) {
echo '<details class="v2-alt" id="v2-alternativen"><summary>Alle '
. count($v2_variants) . ' Bauzustände mit Ersatzteilen anzeigen</summary>';
$v2_alt_open = true;
}
// Dito bei der Hersteller-Rueckfrage: erst die Marke klaeren, die Rohliste
// (oft 20 optisch identische Kacheln) gehoert dahinter.
if (!$v2_alt_open && $v2_brandpick) {
echo '<details class="v2-alt" id="v2-alternativen"><summary>Alle '
. count($results) . ' Treffer ungefiltert anzeigen</summary>';
$v2_alt_open = true;
}
if (isset($d['_mgroup']) && $d['_mgroup'] !== $v2_last_mgroup) {
$v2_last_mgroup = $d['_mgroup'];
echo '<h4 class="v2-mgroup">'.htmlspecialchars($v2_last_mgroup)
. ' <span>'.(int)($v2_mcount[$v2_last_mgroup] ?? 0).'</span></h4>';
}
?>
<div class="v2-dev">
<div class="v2-dev-top">
<div>
<div class="v2-dev-name"><?php echo htmlspecialchars(trim($d['marke'].' '.v2_gname($d))); ?></div>
<div class="v2-dev-meta">
<b>Typ:</b> <?php echo htmlspecialchars($d['typ']); ?>
· <b>Nr:</b> <?php echo htmlspecialchars($d['nr']); ?>
<?php if (!empty($d['produktionsstart']) || !empty($d['produktionsende'])): ?>
· <b>Baujahr:</b> <?php echo htmlspecialchars(trim(($d['produktionsstart']??'').'–'.($d['produktionsende']??''),'–')); ?>
<?php endif; ?>
</div>
</div>
<span class="v2-conf" style="color:<?php echo $ccol; ?>;background:<?php echo $cbg; ?>;">
<?php echo $cicon.' '.htmlspecialchars($clabel); ?>
</span>
</div>
<?php if ($buy && count($buy)): ?>
<div class="v2-parts">
<h4>✓ Sofort erhältlich für dieses Gerät (<?php echo count($buy); ?>):</h4>
<?php foreach (array_slice($buy,0,8) as $b): ?>
<span class="v2-chip v2-buy"><b><?php echo htmlspecialchars($b['number']); ?></b>
· <?php echo htmlspecialchars(mb_strimwidth($b['name'],0,42,'…')); ?>
<?php if ((int)$b['inventory']>0) echo '· '.(int)$b['inventory'].' Stk'; ?></span>
<?php endforeach; ?>
</div>
<?php elseif (count($parts)): ?>
<div class="v2-parts">
<h4><?php echo count($parts); ?> passende Ersatzteile — Auswahl:</h4>
<?php foreach (array_slice($parts,0,10) as $p): ?>
<span class="v2-chip"><b><?php echo htmlspecialchars($p['originalnummer']); ?></b>
<?php if (!empty($p['marke'])) echo '· '.htmlspecialchars($p['marke']); ?></span>
<?php endforeach; ?>
<?php if (count($parts) > 10): ?>
<span class="v2-chip" style="border-style:dashed;color:#999;">+<?php echo count($parts)-10; ?> weitere</span>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php
// Im gefuehrten Modus stecken die schwachen Treffer bereits in $v2_list (nach
// Hersteller gebuendelt), der separate Schwach-Block entfaellt dort komplett.
?>
<?php if (!$v2_guided && count($v2_weak)): ?>
<details class="v2-more">
<summary>Weitere mögliche Geräte anzeigen (<?php echo count($v2_weak); ?>) – schwächere Treffer</summary>
<?php foreach ($v2_weak as $d): list($clabel,$ccol,$cbg,$cicon)=v2_confidence($d['score']); ?>
<div class="v2-dev" style="opacity:.75">
<div class="v2-dev-top">
<div>
<div class="v2-dev-name" style="font-size:15px"><?php echo htmlspecialchars(trim($d['marke'].' '.v2_gname($d))); ?></div>
<div class="v2-dev-meta"><b>Typ:</b> <?php echo htmlspecialchars($d['typ']); ?> · <b>Nr:</b> <?php echo htmlspecialchars($d['nr']); ?></div>
</div>
<span class="v2-conf" style="color:<?php echo $ccol; ?>;background:<?php echo $cbg; ?>;"><?php echo $cicon.' '.htmlspecialchars($clabel); ?></span>
</div>
</div>
<?php endforeach; ?>
</details>
<?php endif; ?>
<?php
// Alternativen-Block schliessen (nur wenn er ueberhaupt geoeffnet wurde).
if ($v2_alt_open) { echo '</details>'; }
?>
<?php $keep_shop = $show_shop_items ? '&shop_items=1' : ''; ?>
<?php if (count($g_buy)): ?>
<div class="v2-shop" id="v2-artikel">
<h3>🛒 Diese Artikel kannst du direkt kaufen</h3>
<?php foreach ($g_buy as $it):
// KEIN Lager-Kriterium mehr: die Kundin fuehrt im Shop kein Lager
// (kein einziger Artikel hat inventory > 0 -- 10.160x 0, 8.724x NULL).
// Bestellbar steuert sie ueber items.active, und searchItems() filtert
// bereits mit WHERE i.active = 1 -> alles hier ist bestellbar.
// Shop-Artikel und Bilder liegen nur auf LIVE -> absolute URLs
$url = 'https://intelectra.de/index.php?item_id=' . (int)$it['id'];
$img = !empty($it['default_image_file_name'])
? 'https://intelectra.de/web/intelectra_shop/images/article/'.rawurlencode($it['default_image_file_name'])
: '';
$pb = isset($it['price_brutto']) ? (float)$it['price_brutto'] : 0;
$bb = !empty($it['bargain_brutto']) ? (float)$it['bargain_brutto'] : 0;
?>
<div class="v2-item">
<a href="<?php echo $url; ?>" target="_blank" rel="noopener"
style="display:flex;align-items:center;gap:14px;min-width:0;text-decoration:none;color:inherit">
<?php if ($img): ?>
<img src="<?php echo $img; ?>" alt="" loading="lazy"
style="width:64px;height:64px;object-fit:contain;background:#fff;border:1px solid #eee;border-radius:6px;flex:0 0 64px"
onerror="this.style.display='none'">
<?php else: ?>
<div style="width:64px;height:64px;flex:0 0 64px;background:#f5f5f5;border:1px dashed #ddd;border-radius:6px;
display:flex;align-items:center;justify-content:center;color:#bbb;font-size:11px">kein Bild</div>
<?php endif; ?>
<div style="min-width:0">
<div class="v2-item-name" style="text-decoration:underline;text-decoration-color:#cfd8dc"><?php echo htmlspecialchars($it['_nml']['clean']); ?></div>
<div class="v2-item-meta">Art-Nr <?php echo htmlspecialchars($it['number']); ?></div>
</div>
</a>
<div style="text-align:right;flex:0 0 auto">
<div style="font-size:17px;font-weight:700;color:#1a1a1a;margin-bottom:2px">
<?php if ($bb > 0 && $pb > 0 && $bb < $pb): ?>
<span style="color:#c62828"><?php echo number_format($bb, 2, ',', '.'); ?>&nbsp;€</span>
<span style="font-size:12px;color:#999;text-decoration:line-through;font-weight:400"><?php echo number_format($pb, 2, ',', '.'); ?>&nbsp;€</span>
<?php elseif ($pb > 0): ?>
<?php echo number_format($pb, 2, ',', '.'); ?>&nbsp;€
<?php else: ?>
<span style="font-size:12px;color:#999;font-weight:400">Preis auf Anfrage</span>
<?php endif; ?>
</div>
<?php if ($pb > 0): ?><div style="font-size:10px;color:#aaa;margin-bottom:4px">inkl. MwSt.</div><?php endif; ?>
<a href="<?php echo $url; ?>" target="_blank" rel="noopener"
class="v2-cart" style="margin-top:6px;text-decoration:none;display:inline-block">
Zum Artikel
</a>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (count($g_succ)): ?>
<div class="v2-shop">
<h3 style="border-left-color:#fb8c00">🔄 Ausgelaufen – aber es gibt einen Nachfolger</h3>
<?php foreach ($g_succ as $it):
$nf = $it['_nml']['nachfolger'];
// (nmle) = ausgelaufener Artikel MIT Nachfolger-Verweis. Der alte Artikel
// existiert im Shop weiterhin und darf deshalb anklickbar sein.
$url_alt = 'https://intelectra.de/index.php?item_id=' . (int)$it['id'];
?>
<div class="v2-item" style="background:#fff8f0;border-color:#ffe0b2">
<div>
<a href="<?php echo $url_alt; ?>" target="_blank" rel="noopener" style="text-decoration:none">
<div class="v2-item-name" style="color:#8a6d3b;text-decoration:line-through;text-decoration-color:#d9b38c">
<?php echo htmlspecialchars($it['_nml']['clean']); ?>
</div>
</a>
<div class="v2-item-meta">Art-Nr <?php echo htmlspecialchars($it['number']); ?> · nicht mehr lieferbar</div>
</div>
<div style="text-align:right">
<div style="font-size:12px;color:#e65100;font-weight:600;margin-bottom:6px">Nachfolger: <?php echo htmlspecialchars($nf); ?></div>
<a href="?q=<?php echo urlencode($nf).$keep_shop; ?>"
class="v2-cart" style="background:#fb8c00;text-decoration:none;display:inline-block">
→ Nachfolger anzeigen
</a>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (count($g_dead)): ?>
<details class="v2-more" style="margin-top:20px">
<summary>Nicht mehr lieferbar, kein Ersatz (<?php echo count($g_dead); ?>) – ausgeblendet</summary>
<?php foreach ($g_dead as $it): ?>
<div class="v2-item" style="opacity:.55">
<div>
<div class="v2-item-name" style="text-decoration:line-through"><?php echo htmlspecialchars($it['_nml']['clean']); ?></div>
<div class="v2-item-meta">Art-Nr <?php echo htmlspecialchars($it['number']); ?></div>
</div>
<div class="v2-stock v2-out" style="white-space:nowrap">✕ entfällt</div>
</div>
<?php endforeach; ?>
</details>
<?php endif; ?>
<?php if (!count($g_buy) && !count($g_succ) && !count($g_dead)): ?>
<!-- keine Artikel -->
<?php endif; ?>
<div class="v2-hint">
💡 <b>Prototyp-Notiz (nicht final):</b> Bild (aus <code>items.default_image_file_name</code>, geladen vom Live-Server)
+ Preis (<code>item_prices</code> Kundengruppe 1, brutto inkl. Steuersatz, Angebotspreis rot) sind jetzt drin.
<b>nml/Nachfolger ist jetzt live:</b> Der Marker <code>(nml)</code>/<code>(nmle)</code> im Artikelnamen wird erkannt —
ausgelaufene Teile <b>mit</b> „Nachfolger &lt;Nr&gt;" landen im orangen Block und verlinken per Klick auf den kaufbaren Nachfolger;
Teile <b>ohne</b> Ersatz werden ans Ende ausgeblendet. Score-Zahlen durch Vertrauens-Text ersetzt.
Tipp: oben „Nur verfügbare Shop-Artikel" aktivieren zeigt pro Gerät die kaufbaren Teile grün.
</div>
</div>
<?php else: ?>
<div class="no-results">
Gib einen Suchbegriff ein (z.B. "AWB 921 PH", "ZCS 2100B", "Kohlefilter Bauknecht")
</div>
<?php endif; ?>
</div>
<script>
function toggleDevice(deviceId) {
const card = document.getElementById('device-' + deviceId);
if (card) {
card.classList.toggle('collapsed');
}
}
</script>
</body>
</html>