diff --git a/src/frontend/static/app.js b/src/frontend/static/app.js index a7f7038..c15622d 100644 --- a/src/frontend/static/app.js +++ b/src/frontend/static/app.js @@ -449,13 +449,53 @@ function daysPhrase(days) { return `по ${forms.slice(0, -1).join(", ")} и ${forms[forms.length - 1]}`; } -/** Описание из таблицы, если оно не сводится к номеру и дням (иначе не показываем). */ +/** + * Дополнение из таблицы: оставляем только фразы, которых нет в разобранных + * атрибутах («без проектора», «МО и СТ»), не разрезая слова. Если описание + * целиком сводится к типу/оснащению/вместимости/номеру/дням — не показываем. + */ function roomInfoText(room) { const info = (room.info || "").trim(); if (!info) return ""; - let rest = info.replace(/\d+/g, ""); - (room.available_days || []).forEach((day) => { rest = rest.split(day).join(""); }); - return rest.replace(/[\s;,.]+/g, "") ? info : ""; + + const known = new Set(); + const addText = (text) => + (text || "") + .toLowerCase() + .split(/[\s;,.:()\/-]+/) + .forEach((word) => { if (word.length >= 2) known.add(word); }); + addText(room.type); + addText(room.type_group); + (room.equipment || []).forEach(addText); + (room.available_days || []).forEach(addText); + + const STOP = new Set(["и", "в", "на", "для", "по", "с", "из", "до", "за", "от", "к", "о", "об", "при", "под", "над", "у"]); + const CAPACITY = /\d+\s*(?:мест[а-яё]*|раб\.?|осн\.?)/gi; + const isKnown = (token) => { + const clean = token.toLowerCase().replace(/[^а-яёa-z0-9]+/g, ""); + if (!clean || !/[а-яёa-z]/.test(clean)) return true; // числа и знаки + if (clean.length < 2) return true; + if (STOP.has(clean)) return true; + if (/^(мест|раб|осн)/.test(clean)) return true; // «место», «раб.» + return [...known].some( + (k) => clean.startsWith(k.slice(0, 4)) || k.startsWith(clean.slice(0, 4)), + ); + }; + + return info + .replace(CAPACITY, " ") + .split(/[;,]/) + .map((part) => part.trim()) + .filter(Boolean) + .map((part) => { + const tokens = part.split(/\s+/); + if (tokens.every(isKnown)) return ""; + const rest = [...tokens]; + while (rest.length && isKnown(rest[0])) rest.shift(); // убираем ведущие известные слова + return rest.join(" "); + }) + .filter(Boolean) + .join("; "); } /** Русское склонение существительного при числе. */