mirror of
https://github.com/wasrusgen/zov-tech.git
synced 2026-06-03 18:04:47 +00:00
user feedback batch: model count, specs, manual link, dimensions, export
1. MODEL COUNT SELECTOR (strategy step): - new PODBOR_MODEL_COUNTS [3/5/7] - state.model_count default '5' - UI on strategy page with description (быстро/оптимально/максимум) 2. AI PROMPT EXPANDED: - new field: manual_search_query — for Google search instruction PDF - new specs object per model: dimensions_mm/volume_l/weight_kg/noise_db/energy_class/color - 'specs ОБЯЗАТЕЛЬНЫ для проектирования кухни' explicit rule - reads checklist.model_count to determine how many models per category - max_tokens 4000 → 8000 (room for richer responses) 3. MODEL CARD RICHER: - _renderSpecsBlock — characteristics in 2-col grid, dimensions highlighted - _renderUtilityLinks — Google search buttons for инструкция (PDF) + Схема установки - Specs critical for ZOV kitchen design (manager needs to verify niche fits) 4. EXPORT BUTTONS: - 'Скачать HTML' — generates standalone HTML with inline styles, downloads as file - 'Печать → PDF' — opens new window with cleaned layout + auto-prints - User can save as PDF via system print dialog 5. PREVIEW updated with realistic specs/manual_query for all 3 fridges
This commit is contained in:
parent
7f417da7e0
commit
ef500fa446
@ -93,7 +93,7 @@ SYSTEM_PROMPT_PICKER = (
|
||||
" «AquaStop (защита от протечек)»\n"
|
||||
" «Инвертор (тише и экономия ~30% электричества)»\n\n"
|
||||
"═══ ФОРМАТ ОТВЕТА ═══\n"
|
||||
"Возвращай **3–5 моделей по КАЖДОЙ категории** (не одну!) — для клиента это выбор.\n"
|
||||
"Количество моделей по категории определяется параметром `checklist.model_count` (3 / 5 / 7) — соблюдай!\n"
|
||||
"Каждая модель ДОЛЖНА содержать аналитику: pros (минимум 3), cons (минимум 2), почему выбрана, с чем сравнивать.\n"
|
||||
"По КАЖДОЙ категории напиши `analysis` — обзор: какие компромиссы, на что обратить внимание.\n"
|
||||
"Валидный JSON без markdown, без ```:\n"
|
||||
@ -109,10 +109,19 @@ SYSTEM_PROMPT_PICKER = (
|
||||
' "price_min_rub": 79990,\n'
|
||||
' "price_max_rub": 92000,\n'
|
||||
' "search_query": "Haier C4F744CMG холодильник",\n'
|
||||
' "manual_search_query": "Haier C4F744CMG manual инструкция pdf",\n'
|
||||
' "highlights": ["NoFrost (не нужно размораживать)", "Инвертор (тише и -30% энергии)"],\n'
|
||||
' "pros": ["тихий 36 дБ — на 4 дБ тише среднего по сегменту", "класс A++, экономия ~30% против A+", "большой объём 463 л против 380 л у конкурентов в той же ценовой категории"],\n'
|
||||
' "cons": ["глубина 660 мм — на 60 мм больше стандартной ниши, проверить нишу клиента", "нет зоны свежести BioFresh — в этом плане Liebherr ровно вдвое лучше"],\n'
|
||||
' "reasoning": "Лучший выбор по цена/качество в этом бюджете. Тише и больше чем Bosch в той же цене, но без премиум-зоны свежести.",\n'
|
||||
' "specs": {\n'
|
||||
' "dimensions_mm": "595×660×2000",\n'
|
||||
' "weight_kg": 75,\n'
|
||||
' "volume_l": 463,\n'
|
||||
' "noise_db": 36,\n'
|
||||
' "energy_class": "A++",\n'
|
||||
' "color": "Нержавеющая сталь"\n'
|
||||
' },\n'
|
||||
' "tier": "middle",\n'
|
||||
' "match_score": 0.92\n'
|
||||
" }\n"
|
||||
@ -132,13 +141,19 @@ SYSTEM_PROMPT_PICKER = (
|
||||
"4. **Cons обязательны**: даже у лучших моделей есть недостатки. Если cons пусто — модель не выбрана. Конкретные минусы: габарит больше ниши, шумнее на 2 дБ, без какой-то функции, цена выше на N%, длительная гарантия только N лет.\n"
|
||||
"5. **Reasoning**: 1 предложение «почему именно эта модель в этом наборе» — позиционирование относительно других в выдаче.\n"
|
||||
"6. **search_query**: точная строка для поиска (бренд + индекс + слово категория). AI агент будет парсить маркетплейсы по этой строке — не указывай лишнего.\n"
|
||||
"7. Бренд-стратегия 'single' — ВСЕ models из одной марки.\n"
|
||||
"8. price_min_rub/price_max_rub — диапазон по разным магазинам (если не уверен — один и тот же)."
|
||||
"7. **manual_search_query**: строка для Google-поиска инструкции, в формате «<brand> <model> manual инструкция pdf»\n"
|
||||
"8. **specs ОБЯЗАТЕЛЬНЫ для проектирования кухни**:\n"
|
||||
" - `dimensions_mm` — габариты ШхГxВ в мм (это критично для дизайна ниш в кухне ЗОВ)\n"
|
||||
" - `weight_kg`, `volume_l` (для холодильников/духовок/ПММ), `noise_db`, `energy_class` ('A+++', 'A++', 'A+', 'A', 'B')\n"
|
||||
" - `color` — основной цвет/материал\n"
|
||||
"9. **Количество моделей в каждой категории = `checklist.model_count`** (3 или 5 или 7). Меньше не возвращай. Если AI не уверен в N-й модели — добавь её всё равно из доступных в РФ.\n"
|
||||
"10. Бренд-стратегия 'single' — ВСЕ models из одной марки.\n"
|
||||
"11. price_min_rub/price_max_rub — диапазон по разным магазинам (если не уверен — один и тот же)."
|
||||
)
|
||||
|
||||
|
||||
def call_ai(user_prompt: str, system_prompt: str | None = None,
|
||||
temperature: float = 0.3, max_tokens: int = 4000) -> dict[str, Any]:
|
||||
temperature: float = 0.3, max_tokens: int = 8000) -> dict[str, Any]:
|
||||
"""Вызов GigaChat. Возвращает {json, text, tokens, model, error?}."""
|
||||
cfg = get_config()
|
||||
try:
|
||||
|
||||
@ -111,6 +111,14 @@ const PODBOR_PICK_STRATEGIES = [
|
||||
{ key: "style", label: "Стилевая согласованность", hint: "единый дизайн-язык всей техники" },
|
||||
];
|
||||
|
||||
/* Сколько моделей предлагать в каждой категории.
|
||||
Меньше = быстрее, больше = больше выбора, но AI ответ дольше и нагрузка на парсеры. */
|
||||
const PODBOR_MODEL_COUNTS = [
|
||||
{ key: "3", label: "3 модели", hint: "быстро · базовый выбор" },
|
||||
{ key: "5", label: "5 моделей", hint: "оптимально · хороший баланс", recommended: true },
|
||||
{ key: "7", label: "7 моделей", hint: "максимум · долго" },
|
||||
];
|
||||
|
||||
/* Параметры по категориям.
|
||||
----------------------------------------------------------
|
||||
Новая схема (иерархический wizard):
|
||||
|
||||
@ -1353,6 +1353,85 @@
|
||||
color: var(--walnut);
|
||||
}
|
||||
|
||||
/* Технические характеристики */
|
||||
.report-specs {
|
||||
margin-top: 10px;
|
||||
background: #FFFCF6;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
.report-specs-head {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.report-specs-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 6px 10px;
|
||||
}
|
||||
.spec-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
.spec-item.highlight {
|
||||
grid-column: 1 / -1;
|
||||
border-bottom: 1px dashed var(--accent-2);
|
||||
padding-bottom: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.spec-label {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 9.5px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--muted);
|
||||
}
|
||||
.spec-value {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--ink);
|
||||
}
|
||||
.spec-item.highlight .spec-value {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--accent-2);
|
||||
}
|
||||
|
||||
/* Утилитарные ссылки — инструкция, схема установки */
|
||||
.report-util-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.util-link {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--ink);
|
||||
background: var(--warm);
|
||||
border: 1px solid var(--line);
|
||||
padding: 5px 10px;
|
||||
border-radius: var(--r-pill);
|
||||
text-decoration: none;
|
||||
transition: background 0.12s;
|
||||
}
|
||||
.util-link:active { background: #EAD9B6; }
|
||||
.util-link--manual { border-color: #6B4A2B; }
|
||||
.util-link--dims { border-color: var(--accent-2); color: var(--accent-2); }
|
||||
|
||||
.report-cat-analysis {
|
||||
font-size: 13.5px;
|
||||
line-height: 1.5;
|
||||
@ -1654,3 +1733,53 @@
|
||||
line-height: 1.5;
|
||||
}
|
||||
.report-warnings > div { margin: 2px 0; }
|
||||
|
||||
/* Экспорт отчёта */
|
||||
.report-export {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: var(--warm);
|
||||
border: 1px dashed var(--walnut);
|
||||
border-radius: var(--r);
|
||||
}
|
||||
.report-export-head {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
color: var(--walnut);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.report-export-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.btn-export {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
padding: 10px 16px;
|
||||
border-radius: 10px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--walnut);
|
||||
color: var(--walnut);
|
||||
cursor: pointer;
|
||||
transition: all 0.12s;
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
}
|
||||
.btn-export:active {
|
||||
background: var(--walnut);
|
||||
color: var(--paper);
|
||||
transform: scale(0.97);
|
||||
}
|
||||
.report-export-hint {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--muted);
|
||||
margin-top: 8px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ const Podbor = (function () {
|
||||
budget_preset: "", // 'luxe'|'premium'|'middle'|'budget'|'exact'
|
||||
price_ranges: {}, // только если budget_preset === 'exact'
|
||||
pick_strategies: [], // ['reviews','balance','tech',...] — multi
|
||||
model_count: "5", // '3' | '5' | '7' — сколько моделей в каждой категории
|
||||
infra: { stove: "", vent: "" },
|
||||
notes: "",
|
||||
};
|
||||
@ -1059,6 +1060,14 @@ const Podbor = (function () {
|
||||
}
|
||||
);
|
||||
|
||||
// Количество моделей в категории
|
||||
const mc = state.model_count || "5";
|
||||
const countGrid = renderPinCards(
|
||||
PODBOR_MODEL_COUNTS,
|
||||
o => (mc === o.key ? "on" : ""),
|
||||
key => { update({ model_count: key }); render(); }
|
||||
);
|
||||
|
||||
const node = el(`
|
||||
<section class="podbor-step">
|
||||
<h2 class="display-title">Стратегия<br><span class="accent">подбора</span></h2>
|
||||
@ -1066,6 +1075,15 @@ const Podbor = (function () {
|
||||
</section>
|
||||
`);
|
||||
node.appendChild(grid);
|
||||
|
||||
const countHead = el(`
|
||||
<div class="block">
|
||||
<div class="block-head">Сколько моделей предложить</div>
|
||||
</div>
|
||||
`);
|
||||
countHead.appendChild(countGrid);
|
||||
node.appendChild(countHead);
|
||||
|
||||
const cta = el(`
|
||||
<div class="podbor-cta-row">
|
||||
<button class="btn-secondary" data-go="budget">Назад</button>
|
||||
@ -1356,9 +1374,99 @@ const Podbor = (function () {
|
||||
wrap.appendChild(wn);
|
||||
}
|
||||
|
||||
// Кнопки экспорта в конце
|
||||
const exportNode = el(`
|
||||
<div class="report-export">
|
||||
<div class="report-export-head">Сохранить отчёт</div>
|
||||
<div class="report-export-buttons">
|
||||
<button class="btn-export" id="exportHtml">⬇ Скачать HTML</button>
|
||||
<button class="btn-export" id="exportPrint">🖨 Печать → PDF</button>
|
||||
</div>
|
||||
<div class="report-export-hint">HTML удобно отправить клиенту в мессенджер · PDF — для печати или вложения</div>
|
||||
</div>
|
||||
`);
|
||||
exportNode.querySelector("#exportHtml").addEventListener("click", () => _exportReportHtml(ai, leadId));
|
||||
exportNode.querySelector("#exportPrint").addEventListener("click", () => _exportReportPrint(wrap, leadId));
|
||||
wrap.appendChild(exportNode);
|
||||
|
||||
return wrap;
|
||||
}
|
||||
|
||||
/* Экспорт: HTML файл с inline стилями и данными — скачивается */
|
||||
function _exportReportHtml(ai, leadId) {
|
||||
// Создаём stand-alone HTML вокруг текущего DOM отчёта
|
||||
const reportEl = document.querySelector(".report");
|
||||
if (!reportEl) return;
|
||||
// Копируем все стили со страницы (link + style)
|
||||
const stylesheets = [];
|
||||
document.querySelectorAll("link[rel='stylesheet'], style").forEach(s => stylesheets.push(s.outerHTML));
|
||||
const html = `<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Подбор техники · ${leadId.slice(0,8)}</title>
|
||||
${stylesheets.join("\n")}
|
||||
<style>
|
||||
body { background: #FBF7F0; padding: 20px; max-width: 900px; margin: 0 auto; }
|
||||
.report-export { display: none; }
|
||||
.podbor-header, .podbor-progress, .cat-strip, #submitResult > .success { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="font-family: 'Newsreader', serif; font-style: italic; color: #1F1A14;">Подбор техники · клиент: ${_esc(state.client_name || "—")}</h1>
|
||||
${reportEl.outerHTML}
|
||||
<footer style="margin-top: 40px; padding: 20px; border-top: 1px solid #ddd; font-size: 11px; color: #888; font-family: 'JetBrains Mono', monospace;">
|
||||
Отчёт сгенерирован ${new Date().toLocaleString("ru-RU")} · ZOV Tech Picker · Lead ID: ${leadId}
|
||||
</footer>
|
||||
</body>
|
||||
</html>`;
|
||||
const blob = new Blob([html], { type: "text/html;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `podbor-${leadId.slice(0,8)}-${(state.client_name || "client").replace(/\s+/g, "_")}.html`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
||||
haptic && haptic("success");
|
||||
}
|
||||
|
||||
/* Экспорт: открываем системный print диалог — пользователь сохраняет как PDF */
|
||||
function _exportReportPrint(reportNode, leadId) {
|
||||
// Открываем новое окно с чистой версткой отчёта только
|
||||
const reportEl = document.querySelector(".report");
|
||||
if (!reportEl) return;
|
||||
const stylesheets = [];
|
||||
document.querySelectorAll("link[rel='stylesheet'], style").forEach(s => stylesheets.push(s.outerHTML));
|
||||
const w = window.open("", "_blank");
|
||||
if (!w) { alert("Браузер заблокировал окно. Разрешите всплывающие окна."); return; }
|
||||
w.document.write(`<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Подбор техники · ${leadId.slice(0,8)} · Печать</title>
|
||||
${stylesheets.join("\n")}
|
||||
<style>
|
||||
body { background: #fff; padding: 20px; max-width: 900px; margin: 0 auto; }
|
||||
.report-export, .podbor-header, .podbor-progress, .cat-strip { display: none; }
|
||||
@media print {
|
||||
body { padding: 10px; }
|
||||
.report-model { page-break-inside: avoid; }
|
||||
.report-cat { page-break-after: auto; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="font-family: 'Newsreader', serif; font-style: italic;">Подбор техники · ${_esc(state.client_name || "—")}</h1>
|
||||
${reportEl.outerHTML}
|
||||
<script>setTimeout(() => window.print(), 500);<\/script>
|
||||
</body>
|
||||
</html>`);
|
||||
w.document.close();
|
||||
haptic && haptic("success");
|
||||
}
|
||||
|
||||
function _renderModelCard(m) {
|
||||
const enriched = m.enriched || {};
|
||||
const pMin = enriched.price_min_rub || m.price_min_rub;
|
||||
@ -1414,8 +1522,12 @@ const Podbor = (function () {
|
||||
</div>
|
||||
` : ""}
|
||||
|
||||
${_renderSpecsBlock(m.specs || {})}
|
||||
|
||||
${m.reasoning ? `<div class="report-reasoning">💡 ${_esc(m.reasoning)}</div>` : ""}
|
||||
|
||||
${_renderUtilityLinks(m)}
|
||||
|
||||
${sourceLinks.length ? `
|
||||
<div class="report-links">
|
||||
<div class="report-links-head">${sourceLinks.length} ${_pluralStores(sourceLinks.length)} нашли товар:</div>
|
||||
@ -1428,6 +1540,53 @@ const Podbor = (function () {
|
||||
return card;
|
||||
}
|
||||
|
||||
/* Спеки технические: габариты, объём, шум, класс энергии, цвет.
|
||||
Габариты — критично для проектирования кухни. */
|
||||
function _renderSpecsBlock(specs) {
|
||||
if (!specs || Object.keys(specs).length === 0) return "";
|
||||
const items = [];
|
||||
if (specs.dimensions_mm) items.push({ label: "Габариты ШхГxВ", value: `${specs.dimensions_mm} мм`, highlight: true });
|
||||
if (specs.volume_l) items.push({ label: "Объём", value: `${specs.volume_l} л` });
|
||||
if (specs.weight_kg) items.push({ label: "Вес", value: `${specs.weight_kg} кг` });
|
||||
if (specs.noise_db) items.push({ label: "Шум", value: `${specs.noise_db} дБ` });
|
||||
if (specs.energy_class) items.push({ label: "Класс энергии", value: specs.energy_class });
|
||||
if (specs.color) items.push({ label: "Цвет / материал", value: specs.color });
|
||||
|
||||
if (!items.length) return "";
|
||||
|
||||
return `
|
||||
<div class="report-specs">
|
||||
<div class="report-specs-head">Характеристики</div>
|
||||
<div class="report-specs-grid">
|
||||
${items.map(i => `
|
||||
<div class="spec-item${i.highlight ? " highlight" : ""}">
|
||||
<div class="spec-label">${_esc(i.label)}</div>
|
||||
<div class="spec-value">${_esc(i.value)}</div>
|
||||
</div>
|
||||
`).join("")}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
/* Кнопки "Инструкция" (Google поиск) + "Габариты" (если есть в specs). */
|
||||
function _renderUtilityLinks(m) {
|
||||
const buttons = [];
|
||||
const manualQuery = m.manual_search_query
|
||||
|| `${m.brand || ""} ${m.model || ""} manual инструкция pdf`.trim();
|
||||
if (manualQuery && manualQuery.length > 5) {
|
||||
const url = `https://www.google.com/search?q=${encodeURIComponent(manualQuery)}`;
|
||||
buttons.push(`<a href="${url}" target="_blank" rel="noopener noreferrer" class="util-link util-link--manual">📄 Инструкция</a>`);
|
||||
}
|
||||
const dims = (m.specs || {}).dimensions_mm;
|
||||
if (dims) {
|
||||
const url = `https://www.google.com/search?q=${encodeURIComponent(`${m.brand} ${m.model} габариты схема установки`)}`;
|
||||
buttons.push(`<a href="${url}" target="_blank" rel="noopener noreferrer" class="util-link util-link--dims">📐 Схема установки</a>`);
|
||||
}
|
||||
if (!buttons.length) return "";
|
||||
return `<div class="report-util-links">${buttons.join("")}</div>`;
|
||||
}
|
||||
|
||||
function _pluralStores(n) {
|
||||
const last = n % 10, lastTwo = n % 100;
|
||||
if (lastTwo >= 11 && lastTwo <= 14) return "магазинов";
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap">
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<link rel="stylesheet" href="assets/styles.css?v=20260511j">
|
||||
<link rel="stylesheet" href="assets/podbor.css?v=20260511j">
|
||||
<link rel="stylesheet" href="assets/styles.css?v=20260511k">
|
||||
<link rel="stylesheet" href="assets/podbor.css?v=20260511k">
|
||||
</head>
|
||||
<body>
|
||||
<main id="app">
|
||||
@ -21,10 +21,10 @@
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="assets/icons.js?v=20260511j"></script>
|
||||
<script src="assets/podbor.config.js?v=20260511j"></script>
|
||||
<script src="assets/podbor.picts.js?v=20260511j"></script>
|
||||
<script src="assets/podbor.js?v=20260511j"></script>
|
||||
<script src="assets/app.js?v=20260511j"></script>
|
||||
<script src="assets/icons.js?v=20260511k"></script>
|
||||
<script src="assets/podbor.config.js?v=20260511k"></script>
|
||||
<script src="assets/podbor.picts.js?v=20260511k"></script>
|
||||
<script src="assets/podbor.js?v=20260511k"></script>
|
||||
<script src="assets/app.js?v=20260511k"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -63,6 +63,8 @@ const MOCK_AI = {
|
||||
pros: ["тихий 36 дБ — на 4 дБ тише среднего по сегменту", "большой объём 463 л против 380 л у Bosch в этой цене", "инвертор + класс A++ — экономия ~30% против A+ моделей", "10 лет гарантии на компрессор"],
|
||||
cons: ["глубина 660 мм — на 60 мм больше стандартной ниши, проверить на замере", "нет зоны свежести BioFresh — в этом плане Liebherr заметно лучше"],
|
||||
reasoning: "Лучший по цена/качество в среднем сегменте. Тише и больше Bosch в той же цене, но без премиум-зоны свежести.",
|
||||
specs: { dimensions_mm: "595×660×2000", volume_l: 463, weight_kg: 75, noise_db: 36, energy_class: "A++", color: "Нержавеющая сталь" },
|
||||
manual_search_query: "Haier C4F744CMG manual инструкция pdf",
|
||||
tier: "middle",
|
||||
enriched: {
|
||||
image_url: "https://placehold.co/200x200/F5EDDC/6B4A2B?text=Haier",
|
||||
@ -81,6 +83,8 @@ const MOCK_AI = {
|
||||
pros: ["премиум-качество немецкой сборки", "очень тихий 34 дБ — на 2 дБ тише Haier", "BioFresh — овощи дольше хрустящие на 30 дней", "10 лет гарантии на компрессор"],
|
||||
cons: ["цена выше Haier на ~50% при том же объёме", "идёт параллельным импортом — ждать 4-6 недель"],
|
||||
reasoning: "Премиум-выбор для тех, кому важна зона свежести и тишина. Переплата ~50% за бренд и BioFresh.",
|
||||
specs: { dimensions_mm: "597×675×2010", volume_l: 372, weight_kg: 89, noise_db: 34, energy_class: "A+++", color: "Нержавеющая сталь SmartSteel" },
|
||||
manual_search_query: "Liebherr CNd 5223 manual инструкция pdf",
|
||||
tier: "premium",
|
||||
enriched: {
|
||||
image_url: "https://placehold.co/200x200/EFE3CC/6B4A2B?text=Liebherr",
|
||||
@ -97,6 +101,8 @@ const MOCK_AI = {
|
||||
pros: ["доступная цена в 2 раза ниже Haier", "компактные габариты 600×600×1900 мм — идеальная ниша", "официальная гарантия 3 года от российского производителя"],
|
||||
cons: ["без инвертора — компрессор работает циклами, заметнее на слух", "шум 42 дБ — на 6 дБ громче Haier", "нет зон свежести"],
|
||||
reasoning: "Страховочный бюджет-вариант если клиент не хочет переплачивать. Российский, доступный, надёжный.",
|
||||
specs: { dimensions_mm: "580×600×1450", volume_l: 240, weight_kg: 52, noise_db: 42, energy_class: "A+", color: "Белый" },
|
||||
manual_search_query: "Бирюса M124 инструкция pdf",
|
||||
tier: "budget",
|
||||
enriched: {
|
||||
image_url: "https://placehold.co/200x200/FBF7F0/6B4A2B?text=Birusa",
|
||||
@ -301,6 +307,33 @@ function _renderModelCard(m) {
|
||||
return "магазинов";
|
||||
}
|
||||
|
||||
// Specs block
|
||||
const specs = m.specs || {};
|
||||
const specsItems = [];
|
||||
if (specs.dimensions_mm) specsItems.push({ label: "Габариты ШхГxВ", value: specs.dimensions_mm + " мм", highlight: true });
|
||||
if (specs.volume_l) specsItems.push({ label: "Объём", value: specs.volume_l + " л" });
|
||||
if (specs.weight_kg) specsItems.push({ label: "Вес", value: specs.weight_kg + " кг" });
|
||||
if (specs.noise_db) specsItems.push({ label: "Шум", value: specs.noise_db + " дБ" });
|
||||
if (specs.energy_class) specsItems.push({ label: "Класс энергии", value: specs.energy_class });
|
||||
if (specs.color) specsItems.push({ label: "Цвет / материал", value: specs.color });
|
||||
const specsHtml = specsItems.length ? `
|
||||
<div class="report-specs">
|
||||
<div class="report-specs-head">Характеристики</div>
|
||||
<div class="report-specs-grid">
|
||||
${specsItems.map(i => `<div class="spec-item${i.highlight ? " highlight" : ""}"><div class="spec-label">${_esc(i.label)}</div><div class="spec-value">${_esc(i.value)}</div></div>`).join("")}
|
||||
</div>
|
||||
</div>` : "";
|
||||
|
||||
// Utility links
|
||||
const utilButtons = [];
|
||||
if (m.manual_search_query) {
|
||||
utilButtons.push(`<a href="https://www.google.com/search?q=${encodeURIComponent(m.manual_search_query)}" target="_blank" class="util-link util-link--manual">📄 Инструкция</a>`);
|
||||
}
|
||||
if (specs.dimensions_mm) {
|
||||
utilButtons.push(`<a href="https://www.google.com/search?q=${encodeURIComponent((m.brand || '') + ' ' + (m.model || '') + ' габариты схема установки')}" target="_blank" class="util-link util-link--dims">📐 Схема установки</a>`);
|
||||
}
|
||||
const utilHtml = utilButtons.length ? `<div class="report-util-links">${utilButtons.join("")}</div>` : "";
|
||||
|
||||
return el(`
|
||||
<article class="report-model">
|
||||
<div class="report-model-img${img ? "" : " placeholder"}">${img ? `<img src="${_esc(img)}" alt="" loading="lazy">` : ""}</div>
|
||||
@ -325,8 +358,12 @@ function _renderModelCard(m) {
|
||||
</div>
|
||||
` : ""}
|
||||
|
||||
${specsHtml}
|
||||
|
||||
${m.reasoning ? `<div class="report-reasoning">💡 ${_esc(m.reasoning)}</div>` : ""}
|
||||
|
||||
${utilHtml}
|
||||
|
||||
${sourceLinks.length ? `
|
||||
<div class="report-links">
|
||||
<div class="report-links-head">${sourceLinks.length} ${_plural(sourceLinks.length)} нашли товар:</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user