mirror of
https://github.com/wasrusgen/zov-tech.git
synced 2026-06-03 16:44:48 +00:00
miniapp: 4 UX fixes from user feedback
1. PHONE NORMALIZATION - On blur (or before submit): '9001234567' -> '+7 900 123-45-67' - Handles 8XXX, 7XXX, +7XXX, 10-digit mobile prefixes - Leaves untouched if not Russian-looking number 2. BRAND LIST FOR RF 2026 - PODBOR_SINGLE_BRAND_OPTIONS updated with realistic 2026 brands - Promoted: Haier, Korting, Midea, Hisense, Бирюса, Атлант, Pozis, DEXP - Bosch/Siemens marked with ⚠ (parallel-import) - Miele/Liebherr/Smeg also marked ⚠ - PODBOR_BRANDS per-category fully refreshed 3. BUDGET ADAPTIVE HINTS - Hints now scale by selected categories share of full kitchen - Just fridge picked → 'Средний' shows ~88-175 тыс instead of 350-700к - Full 8 categories → original 350-700к - PODBOR_BUDGET_SHARES + PODBOR_BUDGET_RANGES constants 4. INFRA STEP CONDITIONAL - Stove power question only shown if hob category picked - Vent question only shown if hood category picked - If neither → step auto-skips to summary (with brief notice) - Summary 'Назад' button respects skip — goes to strategy if needed
This commit is contained in:
parent
44281b1e07
commit
80580db446
@ -50,30 +50,56 @@ const PODBOR_BRAND_STRATEGY = [
|
|||||||
{ key: "different", label: "Разные марки по категориям", hint: "соберём оптимальный микс" },
|
{ key: "different", label: "Разные марки по категориям", hint: "соберём оптимальный микс" },
|
||||||
];
|
];
|
||||||
|
|
||||||
/* Бренды, у которых есть полная линейка кухонной техники (для single-mode) */
|
/* Бренды, у которых есть полная линейка кухонной техники, реально доступные в РФ (2026).
|
||||||
|
tier: premium / middle / budget · note: "available" | "parallel" (параллельный импорт). */
|
||||||
const PODBOR_SINGLE_BRAND_OPTIONS = [
|
const PODBOR_SINGLE_BRAND_OPTIONS = [
|
||||||
{ key: "miele", label: "Miele", tier: "premium" },
|
// Премиум — официально или через параллельный импорт
|
||||||
{ key: "gaggenau", label: "Gaggenau", tier: "premium" },
|
{ key: "miele", label: "Miele", tier: "premium", note: "parallel" },
|
||||||
{ key: "asko", label: "Asko", tier: "premium" },
|
{ key: "asko", label: "Asko", tier: "premium", note: "available" },
|
||||||
{ key: "v_zug", label: "V-ZUG", tier: "premium" },
|
{ key: "smeg", label: "Smeg", tier: "premium", note: "parallel" },
|
||||||
{ key: "neff", label: "Neff", tier: "middle" },
|
{ key: "gorenje", label: "Gorenje", tier: "premium", note: "available" },
|
||||||
{ key: "bosch", label: "Bosch", tier: "middle" },
|
|
||||||
{ key: "siemens", label: "Siemens", tier: "middle" },
|
// Средний — реально работающие бренды
|
||||||
{ key: "electrolux", label: "Electrolux", tier: "middle" },
|
{ key: "haier", label: "Haier", tier: "middle", note: "available" },
|
||||||
{ key: "aeg", label: "AEG", tier: "middle" },
|
{ key: "samsung", label: "Samsung", tier: "middle", note: "available" },
|
||||||
{ key: "samsung", label: "Samsung", tier: "middle" },
|
{ key: "lg", label: "LG", tier: "middle", note: "available" },
|
||||||
{ key: "lg", label: "LG", tier: "middle" },
|
{ key: "korting", label: "Körting", tier: "middle", note: "available" },
|
||||||
{ key: "hansa", label: "Hansa", tier: "budget" },
|
{ key: "midea", label: "Midea", tier: "middle", note: "available" },
|
||||||
{ key: "beko", label: "Beko", tier: "budget" },
|
{ key: "bosch", label: "Bosch ⚠", tier: "middle", note: "parallel" },
|
||||||
|
{ key: "siemens", label: "Siemens ⚠", tier: "middle", note: "parallel" },
|
||||||
|
|
||||||
|
// Бюджет — российские/китайские
|
||||||
|
{ key: "biryusa", label: "Бирюса", tier: "budget", note: "available" },
|
||||||
|
{ key: "atlant", label: "Атлант", tier: "budget", note: "available" },
|
||||||
|
{ key: "pozis", label: "Pozis", tier: "budget", note: "available" },
|
||||||
|
{ key: "hisense", label: "Hisense", tier: "budget", note: "available" },
|
||||||
|
{ key: "hansa", label: "Hansa", tier: "budget", note: "available" },
|
||||||
|
{ key: "dexp", label: "DEXP", tier: "budget", note: "available" },
|
||||||
|
|
||||||
{ key: "ai_pick", label: "Пусть AI выберет под бюджет", recommended: true },
|
{ key: "ai_pick", label: "Пусть AI выберет под бюджет", recommended: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/* Доля бюджета каждой категории от полного комплекта (для адаптивных вилок). */
|
||||||
|
const PODBOR_BUDGET_SHARES = {
|
||||||
|
fridge: 25, hob: 12, oven: 15, dw: 10,
|
||||||
|
hood: 8, microwave: 5, coffee: 15, washer: 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Базовые вилки для ПОЛНОГО комплекта 8 категорий (в тыс. ₽).
|
||||||
|
Адаптируются по выбранным категориям через PODBOR_BUDGET_SHARES. */
|
||||||
|
const PODBOR_BUDGET_RANGES = {
|
||||||
|
luxe: { from: 1500, to: 3000 }, // от 1.5М
|
||||||
|
premium: { from: 700, to: 1500 },
|
||||||
|
middle: { from: 350, to: 700 },
|
||||||
|
budget: { from: 100, to: 350 },
|
||||||
|
};
|
||||||
|
|
||||||
const PODBOR_BUDGET_PRESETS = [
|
const PODBOR_BUDGET_PRESETS = [
|
||||||
{ key: "luxe", label: "Люкс", hint: "от 1.5М ₽ за весь комплект" },
|
{ key: "luxe", label: "Люкс", desc: "лучшее без оглядки на цену" },
|
||||||
{ key: "premium", label: "Премиум", hint: "700к – 1.5М ₽" },
|
{ key: "premium", label: "Премиум", desc: "топовые модели · все опции" },
|
||||||
{ key: "middle", label: "Средний", hint: "350к – 700к ₽", recommended: true },
|
{ key: "middle", label: "Средний", desc: "оптимальный баланс · цена/функции", recommended: true },
|
||||||
{ key: "budget", label: "Бюджет", hint: "до 350к ₽" },
|
{ key: "budget", label: "Бюджет", desc: "только нужное" },
|
||||||
{ key: "exact", label: "Точные цифры", hint: "ввести от-до по категориям" },
|
{ key: "exact", label: "Точные цифры", desc: "вилки от-до по каждой категории" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const PODBOR_PICK_STRATEGIES = [
|
const PODBOR_PICK_STRATEGIES = [
|
||||||
@ -635,47 +661,47 @@ const PODBOR_PARAMS = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Бренды для каждой категории — для чипов с тирами.
|
/* Бренды по категориям (актуально на 2026, РФ).
|
||||||
Сокращённый набор; полный список можно расширить из исходного HTML. */
|
⚠ — параллельный импорт, остальные — официально доступны. */
|
||||||
const PODBOR_BRANDS = {
|
const PODBOR_BRANDS = {
|
||||||
fridge: {
|
fridge: {
|
||||||
premium: ["Liebherr", "Miele", "Sub-Zero", "V-ZUG"],
|
premium: ["Miele ⚠", "Liebherr ⚠", "Asko", "Gorenje"],
|
||||||
middle: ["Bosch", "Siemens", "Samsung", "LG"],
|
middle: ["Haier", "Samsung", "LG", "Korting", "Bosch ⚠", "Siemens ⚠"],
|
||||||
budget: ["Indesit", "Beko", "Hotpoint"],
|
budget: ["Бирюса", "Атлант", "Pozis", "Hisense", "Indesit", "Hansa"],
|
||||||
},
|
},
|
||||||
hob: {
|
hob: {
|
||||||
premium: ["Miele", "Gaggenau", "AEG"],
|
premium: ["Miele ⚠", "Asko", "Gorenje", "Smeg ⚠"],
|
||||||
middle: ["Bosch", "Siemens", "Electrolux", "Hansa"],
|
middle: ["Korting", "Haier", "Midea", "Bosch ⚠", "Siemens ⚠"],
|
||||||
budget: ["Hotpoint", "Beko", "Indesit"],
|
budget: ["Hansa", "Hisense", "DEXP", "Дарина"],
|
||||||
},
|
},
|
||||||
oven: {
|
oven: {
|
||||||
premium: ["Miele", "Gaggenau", "Neff"],
|
premium: ["Miele ⚠", "Asko", "Gorenje", "Smeg ⚠"],
|
||||||
middle: ["Bosch", "Siemens", "Electrolux", "AEG"],
|
middle: ["Korting", "Haier", "Midea", "Samsung", "Bosch ⚠"],
|
||||||
budget: ["Hansa", "Beko", "Hotpoint"],
|
budget: ["Hansa", "Hisense", "DEXP", "Дарина"],
|
||||||
},
|
},
|
||||||
dw: {
|
dw: {
|
||||||
premium: ["Miele", "Asko", "V-ZUG"],
|
premium: ["Miele ⚠", "Asko", "Gorenje"],
|
||||||
middle: ["Bosch", "Siemens", "Electrolux"],
|
middle: ["Haier", "Midea", "Korting", "Bosch ⚠"],
|
||||||
budget: ["Hansa", "Beko", "Indesit"],
|
budget: ["Hansa", "Hisense", "Indesit"],
|
||||||
},
|
},
|
||||||
hood: {
|
hood: {
|
||||||
premium: ["Miele", "Falmec", "Faber"],
|
premium: ["Miele ⚠", "Falmec ⚠", "Faber ⚠", "Gorenje"],
|
||||||
middle: ["Bosch", "Siemens", "Elica"],
|
middle: ["Korting", "Maunfeld", "Elikor", "Haier"],
|
||||||
budget: ["Hansa", "Hotpoint", "Maunfeld"],
|
budget: ["Hansa", "Hisense", "DEXP", "Krona"],
|
||||||
},
|
},
|
||||||
microwave: {
|
microwave: {
|
||||||
premium: ["Miele", "Neff"],
|
premium: ["Miele ⚠", "Asko"],
|
||||||
middle: ["Bosch", "Siemens", "Samsung", "LG"],
|
middle: ["Samsung", "LG", "Haier", "Midea", "Bosch ⚠"],
|
||||||
budget: ["Whirlpool", "Hansa", "Beko"],
|
budget: ["Hansa", "Hisense", "DEXP", "Polaris"],
|
||||||
},
|
},
|
||||||
coffee: {
|
coffee: {
|
||||||
premium: ["Miele", "Jura", "De'Longhi PrimaDonna"],
|
premium: ["Miele ⚠", "Jura ⚠", "Saeco ⚠"],
|
||||||
middle: ["De'Longhi", "Saeco", "Bosch"],
|
middle: ["De'Longhi ⚠", "Philips ⚠", "Polaris", "Bork ⚠"],
|
||||||
budget: ["Krups", "Philips"],
|
budget: ["Polaris", "Redmond", "Kitfort"],
|
||||||
},
|
},
|
||||||
washer: {
|
washer: {
|
||||||
premium: ["Miele", "Asko", "V-ZUG"],
|
premium: ["Miele ⚠", "Asko", "Gorenje"],
|
||||||
middle: ["Bosch", "Siemens", "Samsung", "LG"],
|
middle: ["Haier", "Samsung", "LG", "Korting", "Bosch ⚠"],
|
||||||
budget: ["Indesit", "Hotpoint", "Beko"],
|
budget: ["Атлант", "Indesit", "Hansa", "Hisense"],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -892,8 +892,26 @@ const Podbor = (function () {
|
|||||||
|
|
||||||
function renderBudget() {
|
function renderBudget() {
|
||||||
const bp = state.budget_preset || "";
|
const bp = state.budget_preset || "";
|
||||||
|
|
||||||
|
// Считаем суммарную долю выбранных категорий от полного комплекта
|
||||||
|
const share = (state.categories || []).reduce(
|
||||||
|
(s, c) => s + (PODBOR_BUDGET_SHARES[c] || 0), 0
|
||||||
|
) / 100;
|
||||||
|
const shareSafe = share > 0 ? share : 1;
|
||||||
|
|
||||||
|
// Подмешиваем hint с реальной вилкой для выбранных категорий
|
||||||
|
const presetsWithRange = PODBOR_BUDGET_PRESETS.map(o => {
|
||||||
|
if (o.key === "exact") return { ...o, hint: o.desc };
|
||||||
|
const r = PODBOR_BUDGET_RANGES[o.key];
|
||||||
|
if (!r) return { ...o, hint: o.desc };
|
||||||
|
const from = Math.round(r.from * shareSafe);
|
||||||
|
const to = Math.round(r.to * shareSafe);
|
||||||
|
const label = from >= 1000 ? `${(from/1000).toFixed(1)}–${(to/1000).toFixed(1)}М ₽` : `${from}–${to} тыс ₽`;
|
||||||
|
return { ...o, hint: `${label} · ${o.desc}` };
|
||||||
|
});
|
||||||
|
|
||||||
const presetGrid = renderPinCards(
|
const presetGrid = renderPinCards(
|
||||||
PODBOR_BUDGET_PRESETS,
|
presetsWithRange,
|
||||||
o => (bp === o.key ? "on" : ""),
|
o => (bp === o.key ? "on" : ""),
|
||||||
key => { update({ budget_preset: key }); render(); }
|
key => { update({ budget_preset: key }); render(); }
|
||||||
);
|
);
|
||||||
@ -1010,10 +1028,24 @@ const Podbor = (function () {
|
|||||||
/* ===================== Step: infra ===================== */
|
/* ===================== Step: infra ===================== */
|
||||||
|
|
||||||
function renderInfra() {
|
function renderInfra() {
|
||||||
const node = el(`
|
const cats = state.categories || [];
|
||||||
|
const askStove = cats.includes("hob");
|
||||||
|
const askVent = cats.includes("hood");
|
||||||
|
|
||||||
|
// Если ни одна из релевантных категорий не выбрана — пропускаем шаг
|
||||||
|
if (!askStove && !askVent) {
|
||||||
|
// Автопереход на summary через микропаузу (чтобы пользователь увидел)
|
||||||
|
setTimeout(() => { go("summary"); }, 50);
|
||||||
|
return el(`
|
||||||
<section class="podbor-step">
|
<section class="podbor-step">
|
||||||
<h2 class="display-title">Инфраструктура<br><span class="accent">кухни</span></h2>
|
<p class="lede" style="text-align:center;padding:30px;">
|
||||||
<p class="lede">Газ или электрика — определит тип варочной. Подключение вытяжки — нужны ли выводы или угольный фильтр.</p>
|
Инфраструктурные вопросы для выбранных категорий не требуются — переходим к итогу...
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stoveBlock = askStove ? `
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<div class="block-head">Подключение варочной</div>
|
<div class="block-head">Подключение варочной</div>
|
||||||
<div class="opt-list">
|
<div class="opt-list">
|
||||||
@ -1022,6 +1054,9 @@ const Podbor = (function () {
|
|||||||
`).join("")}
|
`).join("")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
` : "";
|
||||||
|
|
||||||
|
const ventBlock = askVent ? `
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<div class="block-head">Вытяжка → внутридомовая вентиляция?</div>
|
<div class="block-head">Вытяжка → внутридомовая вентиляция?</div>
|
||||||
<div class="opt-list">
|
<div class="opt-list">
|
||||||
@ -1031,6 +1066,20 @@ const Podbor = (function () {
|
|||||||
</div>
|
</div>
|
||||||
<div class="hint">Если «Нет» — менеджер закладывает угольный фильтр. Если «Да» — заранее планируем выводы.</div>
|
<div class="hint">Если «Нет» — менеджер закладывает угольный фильтр. Если «Да» — заранее планируем выводы.</div>
|
||||||
</div>
|
</div>
|
||||||
|
` : "";
|
||||||
|
|
||||||
|
const lede = (askStove && askVent)
|
||||||
|
? "Газ или электрика — определит тип варочной. Подключение вытяжки — нужны ли выводы или угольный фильтр."
|
||||||
|
: askStove
|
||||||
|
? "Газ или электрика — определит тип варочной (индукция / стеклокерамика / газ)."
|
||||||
|
: "Подключение вытяжки — нужны ли выводы в вентшахту или угольный фильтр.";
|
||||||
|
|
||||||
|
const node = el(`
|
||||||
|
<section class="podbor-step">
|
||||||
|
<h2 class="display-title">Инфраструктура<br><span class="accent">кухни</span></h2>
|
||||||
|
<p class="lede">${lede}</p>
|
||||||
|
${stoveBlock}
|
||||||
|
${ventBlock}
|
||||||
<div class="podbor-cta-row">
|
<div class="podbor-cta-row">
|
||||||
<button class="btn-secondary" data-go="strategy">Назад</button>
|
<button class="btn-secondary" data-go="strategy">Назад</button>
|
||||||
<button class="btn-primary" data-go="summary">Дальше</button>
|
<button class="btn-primary" data-go="summary">Дальше</button>
|
||||||
@ -1103,7 +1152,7 @@ const Podbor = (function () {
|
|||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="podbor-cta-row">
|
<div class="podbor-cta-row">
|
||||||
<button class="btn-secondary" data-go="infra">Назад</button>
|
<button class="btn-secondary" id="summaryBack">Назад</button>
|
||||||
<button class="btn-primary" id="submitBtn">Отправить · AI подберёт</button>
|
<button class="btn-primary" id="submitBtn">Отправить · AI подберёт</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1112,6 +1161,12 @@ const Podbor = (function () {
|
|||||||
`);
|
`);
|
||||||
bindInputs(node);
|
bindInputs(node);
|
||||||
bindNav(node);
|
bindNav(node);
|
||||||
|
// Кнопка "Назад" — обходим infra если она авто-пропускается
|
||||||
|
node.querySelector("#summaryBack").addEventListener("click", () => {
|
||||||
|
const cats = state.categories || [];
|
||||||
|
const goTo = (cats.includes("hob") || cats.includes("hood")) ? "infra" : "strategy";
|
||||||
|
go(goTo);
|
||||||
|
});
|
||||||
node.querySelector("#submitBtn").addEventListener("click", () => onSubmit(node));
|
node.querySelector("#submitBtn").addEventListener("click", () => onSubmit(node));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -1131,6 +1186,11 @@ const Podbor = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Финальная нормализация телефона перед отправкой
|
||||||
|
const normPhone = normalizePhone(state.client_phone || "");
|
||||||
|
if (normPhone && normPhone !== state.client_phone) {
|
||||||
|
update({ client_phone: normPhone });
|
||||||
|
}
|
||||||
const res = await fetch(`${BACKEND_URL}/api/podbor`, {
|
const res = await fetch(`${BACKEND_URL}/api/podbor`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@ -1335,8 +1395,30 @@ const Podbor = (function () {
|
|||||||
inp.addEventListener("input", e => {
|
inp.addEventListener("input", e => {
|
||||||
update({ [e.target.dataset.bind]: e.target.value });
|
update({ [e.target.dataset.bind]: e.target.value });
|
||||||
});
|
});
|
||||||
|
// Нормализация телефона на blur
|
||||||
|
if (inp.dataset.bind === "client_phone") {
|
||||||
|
inp.addEventListener("blur", e => {
|
||||||
|
const normalized = normalizePhone(e.target.value);
|
||||||
|
if (normalized && normalized !== e.target.value) {
|
||||||
|
e.target.value = normalized;
|
||||||
|
update({ client_phone: normalized });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Приводим телефон к единому формату +7 XXX XXX-XX-XX.
|
||||||
|
Принимает: 8XXXXXXXXXX, 7XXXXXXXXXX, +7XXXXXXXXXX, 9XXXXXXXXX (без префикса). */
|
||||||
|
function normalizePhone(raw) {
|
||||||
|
if (!raw) return "";
|
||||||
|
const digits = raw.replace(/\D/g, "");
|
||||||
|
let d = digits;
|
||||||
|
if (d.length === 11 && d.startsWith("8")) d = "7" + d.slice(1);
|
||||||
|
if (d.length === 10 && d.startsWith("9")) d = "7" + d; // мобильный без префикса
|
||||||
|
if (d.length !== 11 || !d.startsWith("7")) return raw.trim(); // не похоже на РФ-номер — не трогаем
|
||||||
|
return `+7 ${d.slice(1, 4)} ${d.slice(4, 7)}-${d.slice(7, 9)}-${d.slice(9, 11)}`;
|
||||||
|
}
|
||||||
|
|
||||||
function bindNav(node) {
|
function bindNav(node) {
|
||||||
node.querySelectorAll("[data-go]").forEach(b => {
|
node.querySelectorAll("[data-go]").forEach(b => {
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<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">
|
<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>
|
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||||
<link rel="stylesheet" href="assets/styles.css?v=20260511e">
|
<link rel="stylesheet" href="assets/styles.css?v=20260511f">
|
||||||
<link rel="stylesheet" href="assets/podbor.css?v=20260511e">
|
<link rel="stylesheet" href="assets/podbor.css?v=20260511f">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main id="app">
|
<main id="app">
|
||||||
@ -21,10 +21,10 @@
|
|||||||
<div class="spinner"></div>
|
<div class="spinner"></div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<script src="assets/icons.js?v=20260511e"></script>
|
<script src="assets/icons.js?v=20260511f"></script>
|
||||||
<script src="assets/podbor.config.js?v=20260511e"></script>
|
<script src="assets/podbor.config.js?v=20260511f"></script>
|
||||||
<script src="assets/podbor.picts.js?v=20260511e"></script>
|
<script src="assets/podbor.picts.js?v=20260511f"></script>
|
||||||
<script src="assets/podbor.js?v=20260511e"></script>
|
<script src="assets/podbor.js?v=20260511f"></script>
|
||||||
<script src="assets/app.js?v=20260511e"></script>
|
<script src="assets/app.js?v=20260511f"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user