Initial commit: site monorepo with API, web, and infra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Человекочитаемые title/detail для центра уведомлений.
|
||||
*/
|
||||
(function (global) {
|
||||
const MONTHS = [
|
||||
"января",
|
||||
"февраля",
|
||||
"марта",
|
||||
"апреля",
|
||||
"мая",
|
||||
"июня",
|
||||
"июля",
|
||||
"августа",
|
||||
"сентября",
|
||||
"октября",
|
||||
"ноября",
|
||||
"декабря",
|
||||
];
|
||||
|
||||
function formatWhen(date) {
|
||||
const d = date instanceof Date ? date : new Date();
|
||||
const day = d.getDate();
|
||||
const month = MONTHS[d.getMonth()];
|
||||
const year = d.getFullYear();
|
||||
const hh = String(d.getHours()).padStart(2, "0");
|
||||
const mm = String(d.getMinutes()).padStart(2, "0");
|
||||
return `${day} ${month} ${year}, ${hh}:${mm}`;
|
||||
}
|
||||
|
||||
function normalizeTitle(text) {
|
||||
const t = String(text || "").trim();
|
||||
if (/^Сохранено\b/i.test(t)) return "Сохранено";
|
||||
return t || "Уведомление";
|
||||
}
|
||||
|
||||
function detectCategory(page, text, record) {
|
||||
if (record.category) return record.category;
|
||||
if (page === "recipes") return "recipe";
|
||||
if (page === "components") return "component";
|
||||
if (page === "feed_consumption") return "sklad";
|
||||
if (page === "feed_dispensers") return "equipment";
|
||||
if (page === "reports") return "report";
|
||||
if (record.category === "feed_quality") return "feed_quality";
|
||||
if (record.category === "daily_plan") return "daily_plan";
|
||||
if (page === "daily_plan") return "daily_plan";
|
||||
const lower = text.toLowerCase();
|
||||
if (
|
||||
lower.includes("план на день") ||
|
||||
lower.includes("из плана") ||
|
||||
lower.includes("в плане") ||
|
||||
lower.includes("замен")
|
||||
) {
|
||||
return "daily_plan";
|
||||
}
|
||||
if (lower.includes("рейс") || lower.includes("рецепт")) return "recipe";
|
||||
if (lower.includes("компонент")) return "component";
|
||||
if (lower.includes("склад") || lower.includes("остат")) return "sklad";
|
||||
if (lower.includes("синхрон")) return "sync";
|
||||
if (lower.includes("перегруз") || lower.includes("недогруз") || lower.includes("миксер") || lower.includes("смешиван")) return "feed_quality";
|
||||
return "general";
|
||||
}
|
||||
|
||||
function resolvePage(explicit) {
|
||||
if (explicit) return explicit;
|
||||
const path = (global.location && global.location.pathname) || "";
|
||||
if (path.startsWith("/recipes")) return "recipes";
|
||||
if (path.startsWith("/components")) return "components";
|
||||
if (path.startsWith("/feed_dispensers")) return "feed_dispensers";
|
||||
if (path.startsWith("/reports")) return "reports";
|
||||
if (path.startsWith("/feed_consumption")) return "feed_consumption";
|
||||
return "general";
|
||||
}
|
||||
|
||||
function q(name) {
|
||||
return name ? `«${name}»` : "";
|
||||
}
|
||||
|
||||
function buildNotificationRecord(kind, plainText, opts) {
|
||||
const options = opts && typeof opts === "object" ? opts : {};
|
||||
const record = options.record && typeof options.record === "object" ? options.record : {};
|
||||
const when = formatWhen();
|
||||
const page = resolvePage(record.page || options.page);
|
||||
const text = String(plainText || "").trim();
|
||||
let title = record.title || normalizeTitle(text);
|
||||
let detail = record.detail || "";
|
||||
|
||||
if (!detail) {
|
||||
const recipe = record.recipeName || record.recipe;
|
||||
const component = record.componentName || record.component;
|
||||
const period = record.periodName || record.period;
|
||||
|
||||
if (/^Сохранено$/i.test(title) && recipe) {
|
||||
detail = `Рейс ${q(recipe)} сохранён — ${when}`;
|
||||
} else if (/рейс удал/i.test(text) && recipe && period) {
|
||||
detail = `Рейс ${q(recipe)} удалён из периода ${q(period)} — ${when}`;
|
||||
} else if (/рейс удал/i.test(text) && recipe) {
|
||||
detail = `Рейс ${q(recipe)} удалён — ${when}`;
|
||||
} else if (/рейс скопирован/i.test(text) && recipe) {
|
||||
detail = `Рейс ${q(recipe)} скопирован — ${when}`;
|
||||
} else if (/вставлен из буфера/i.test(text)) {
|
||||
detail = `Рейс вставлен из буфера — ${when}`;
|
||||
} else if (/перенес/i.test(text) && recipe && period) {
|
||||
detail = `Рейс ${q(recipe)} перенесён в период ${q(period)} — ${when}`;
|
||||
} else if (/компонент добавлен/i.test(text) && component) {
|
||||
detail = `Компонент ${q(component)} добавлен — ${when}`;
|
||||
} else if (/компонент обнов/i.test(text) && component) {
|
||||
detail = `Компонент ${q(component)} обновлён — ${when}`;
|
||||
} else if (/компонент удал/i.test(text) && component) {
|
||||
detail = `Компонент ${q(component)} удалён — ${when}`;
|
||||
} else if (/убрано со склада/i.test(text) && component) {
|
||||
detail = `Компонент ${q(component)} убран со склада — ${when}`;
|
||||
} else if (/на склад/i.test(text) && component) {
|
||||
detail = `Компонент ${q(component)} добавлен на склад — ${when}`;
|
||||
} else if (/настройки сохранены/i.test(text)) {
|
||||
detail = `Настройки сохранены — ${when}`;
|
||||
} else if (record.category === "feed_quality" || page === "reports" && /перегруз|недогруз|миксер|смешиван/i.test(text)) {
|
||||
detail = record.detail || (text ? `${text} — ${when}` : `Отклонение по рейсу — ${when}`);
|
||||
} else if (text) {
|
||||
detail = `${text} — ${when}`;
|
||||
} else {
|
||||
detail = `Событие — ${when}`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
detail,
|
||||
kind: kind || "info",
|
||||
category: detectCategory(page, text, record),
|
||||
page,
|
||||
linkKind:
|
||||
record.linkKind ||
|
||||
(page === "components"
|
||||
? "component"
|
||||
: page === "feed_consumption"
|
||||
? "sklad"
|
||||
: page === "feed_dispensers"
|
||||
? "equipment"
|
||||
: null),
|
||||
};
|
||||
}
|
||||
|
||||
global.WespZootechNotificationMessages = {
|
||||
formatWhen,
|
||||
buildNotificationRecord,
|
||||
resolvePage,
|
||||
};
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
Reference in New Issue
Block a user