Страница построена на реальных данных 12 STOREEZ. Ниже — источники, правила расчёта и то, что нужно знать, прежде чем принимать по этим цифрам решения.
Всё берётся из Google-таблицы «проверки», собирается скриптом
node scripts/build_landing_data.js и складывается в data.js.
Руками этот файл не правят — правки затрутся следующей сборкой.
| Что | Откуда | Объём |
|---|---|---|
| Дивизионы и магазины | scripts/lib/qa_stores.js — схема управления розницей | 6 дивизионов, 51 магазин |
| Проверки | вкладка QA_STORE_WEEK | 2 119 проверок трёх видов |
| Отзывы и оценки | вкладка VoC | 11 539 строк, из них 2 359 с текстом |
Доля позитива — это не проверка, а доля: сколько оценок «5» среди всех оценок и обращений клиентов за период. Она хранится недельными корзинами «пятёрки / все оценки», которые складываются, и только потом берётся отношение. Поэтому месяц и год — строгая доля, а не среднее из недельных процентов.
Доля показывается только при 5 и более оценках за период. Ниже этого порога она скачет на одном отзыве: медиана — 7 оценок на магазин за неделю, и при пороге в 3 ровно половина недель давала бы ровные «100%».
Простое среднее тех составляющих, по которым за выбранный период есть значение. Отсутствующая составляющая не считается нулём и не входит в знаменатель. Если нет ничего — выводится «Нет данных», а не ноль.
Пример: Internal Audit 90, Video Check List 95, Доля позитива 92, Mystery Shopper за период не проводился → (90 + 95 + 92) / 3 = 92,3.
На уровнях «Retail» и «Дивизион» проценты позитива и негатива считаются суммой отзывов, а не средним процентов по магазинам. Разница не косметическая: на текущих данных строгая доля позитива по рознице — 56,7%, тогда как наивное среднее по магазинам дало бы 53,9%.
Тональность: оценка «5» — позитив, оценки 1–4 — негатив. Это методика, принятая в проекте. Нейтральной категории в модели нет.
Дельта — разница с предыдущим аналогичным периодом. Знак и стрелка проставлены всегда, цвет нигде не является единственным носителем смысла.
Магазин помечается бордовым при балле ниже 85, падении от 3 пунктов или доле негатива выше 45% при базе от 8 отзывов. Пороги демонстрационные и подлежат согласованию.
Страница размещена на внешнем сервере, поэтому тексты отзывов проходят обезличивание на этапе сборки. В исходной таблице ничего не меняется.
[имя][телефон], адреса почты → [почта][номер][дата]Обезличено 436 текстов из 2 359, всего 496 замен. Смысл и тональность цитаты сохраняются полностью: маскируется только то, что позволяет опознать человека.
Правило намеренно консервативно в одну сторону: слово маскируется только рядом с маркером (должность, «зовут», благодарность) и с заглавной буквы. Иначе под «имя» попадали обычные слова — «Директор отказалась продать», «консультантов достаточно». Города, названия ТЦ и бренд не трогаются.
Store = «-» (ecom и доставка), остальные — выведенные из отчётности точки
(Большая Конюшенная, Атриум, Европолис СПб, Мега Химки Аутлет) и не-магазины.data.js. Четыре плоских массива плюс positivity. Знает про источник, не знает про расчёты и вёрстку.CALC в начале app.js: чистые функции без обращений к DOM.app.js. Получает цифры только через aggregate(), сам ничего не вычисляет.# обезличенные цитаты (по умолчанию) — этот вариант уходит на сервер
node scripts/build_landing_data.js
# исходные тексты, только для локального просмотра
node scripts/build_landing_data.js --raw-quotes
# совсем без текстов, только агрегаты
node scripts/build_landing_data.js --no-quotes
Интерфейс обращается к данным ровно один раз — window.DATA_SOURCE.load().
Достаточно вернуть из него объект той же формы:
{ divisions: [{ id, name }],
stores: [{ id, division_id, name, city }],
checks: [{ id, store_id, type, date, score }], // type: audit|video|mystery
voc_reviews:[{ id, store_id, date, sentiment, topic, text }],
positivity: [{ store_id, date, five, all }] } // date = понедельник недели
date — строка YYYY-MM-DD; недели, месяцы и годы считаются на клиенте.score — число или null. Отсутствие оценки передавать именно как null, не нулём.sentiment — positive либо negative.app.js и index.html при этом не трогаются.Источник данных: Google Sheets.