wasrusgen1-crm/docs/data.js

162 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @wasrusgen1 CRM — Единый источник данных
* Подключается во все кабинеты: <script src="data.js"></script>
* Содержит: вертикаль управления, менеджеры, расписание, заявки, статистика
* Версия: 2026-05-28
*/
// ═══════════════════════════════════════════════════════════════════
// ВЕРТИКАЛЬ: КД → АДМИНИСТРАТОР → МЕНЕДЖЕРЫ
// Единый источник истины для всех кабинетов
// ═══════════════════════════════════════════════════════════════════
var _HIERARCHY = [
{
salonId:'lenina', salon:'Салон Ленина', color:'#3B82F6',
admin:{name:'Анна М.', short:'АМ', userId:'admin_lenina'},
orders:27, ordersPlan:30, revenue:1537000, revenuePlan:1700000,
overdue:1, overdueRisk:98500, purchases:2, newLeads:14, status:'warn',
managers:[
{id:'ak', name:'Анна К.', short:'АК', color:'#7C3AED', salon:'lenina', visits:42, deals:14, revenue:847000, conversion:33, avg:60500, rating:4.8, active:true},
{id:'ms', name:'Мария С.', short:'МС', color:'#0891B2', salon:'lenina', visits:35, deals:9, revenue:610000, conversion:26, avg:67800, rating:4.5, active:true},
]
},
{
salonId:'pobedy', salon:'Салон Победы', color:'#8B5CF6',
admin:{name:'Ирина С.', short:'ИС', userId:'admin_pobedy'},
orders:20, ordersPlan:22, revenue:1310000, revenuePlan:1500000,
overdue:1, overdueRisk:113000, purchases:1, newLeads:12, status:'warn',
managers:[
{id:'pv', name:'Пётр В.', short:'ПВ', color:'#059669', salon:'pobedy', visits:28, deals:7, revenue:490000, conversion:25, avg:70000, rating:4.3, active:true},
{id:'iv', name:'Иван В.', short:'ИВ', color:'#D97706', salon:'pobedy', visits:31, deals:8, revenue:530000, conversion:26, avg:66250, rating:4.1, active:false},
]
},
];
// ═══════════════════════════════════════════════════════════════════
// ПЛОСКИЙ СПИСОК ВСЕХ МЕНЕДЖЕРОВ (производный от _HIERARCHY)
// ═══════════════════════════════════════════════════════════════════
var _CHESS_MGRS = (function(){
var list = [];
_HIERARCHY.forEach(function(h){
h.managers.forEach(function(m){ list.push(m); });
});
return list;
})();
// ═══════════════════════════════════════════════════════════════════
// ШАХМАТКА: временные слоты и расписание
// ═══════════════════════════════════════════════════════════════════
var _CHESS_HOURS = ['10:00','11:00','12:00','13:00','14:00','15:00','16:00','17:00','18:00','19:00','20:00'];
var _CHESS_DATA = {
'ak':{'10:00':{client:'Орлова М.', type:'consult', status:'done'},
'11:00':{client:'Соколов А.', type:'follow', status:'done'},
'12:00':{client:'', type:'', status:'free'},
'13:00':{client:'', type:'', status:'free'},
'14:00':{client:'Ким Л.', type:'consult', status:'busy'},
'15:00':{client:'Ким Л.', type:'consult', status:'busy'},
'16:00':{client:'Захаров П.', type:'measure', status:'busy'},
'17:00':{client:'Новикова С.', type:'consult', status:'free'},
'18:00':{client:'', type:'', status:'free'},
'19:00':{client:'Громов И.', type:'follow', status:'free'},
'20:00':{client:'', type:'', status:'free'}},
'ms':{'10:00':{client:'Козлов Р.', type:'follow', status:'done'},
'11:00':{client:'', type:'', status:'free'},
'12:00':{client:'Лебедев С.', type:'consult', status:'done'},
'13:00':{client:'', type:'', status:'free'},
'14:00':{client:'Петрова А.', type:'tech', status:'busy'},
'15:00':{client:'Петрова А.', type:'tech', status:'busy'},
'16:00':{client:'', type:'', status:'free'},
'17:00':{client:'Морозов В.', type:'consult', status:'busy'},
'18:00':{client:'', type:'', status:'free'},
'19:00':{client:'', type:'', status:'free'},
'20:00':{client:'', type:'', status:'free'}},
'pv':{'10:00':{client:'', type:'', status:'free'},
'11:00':{client:'Сидорова Н.', type:'consult', status:'done'},
'12:00':{client:'Фёдоров К.', type:'follow', status:'noshow'},
'13:00':{client:'', type:'', status:'free'},
'14:00':{client:'', type:'', status:'free'},
'15:00':{client:'Баринова Т.', type:'consult', status:'busy'},
'16:00':{client:'Баринова Т.', type:'consult', status:'busy'},
'17:00':{client:'', type:'', status:'free'},
'18:00':{client:'Яковлев М.', type:'measure', status:'busy'},
'19:00':{client:'Яковлев М.', type:'measure', status:'busy'},
'20:00':{client:'', type:'', status:'free'}},
'iv':{'10:00':{client:'Тихонова Р.', type:'consult', status:'done'},
'11:00':{client:'Тихонова Р.', type:'consult', status:'done'},
'12:00':{client:'', type:'', status:'free'},
'13:00':{client:'Волков Е.', type:'follow', status:'done'},
'14:00':{client:'', type:'', status:'free'},
'15:00':{client:'Кузьмин О.', type:'consult', status:'busy'},
'16:00':{client:'', type:'', status:'free'},
'17:00':{client:'Рыбаков Д.', type:'tech', status:'free'},
'18:00':{client:'Рыбаков Д.', type:'tech', status:'free'},
'19:00':{client:'', type:'', status:'free'},
'20:00':{client:'', type:'', status:'free'}},
};
// ═══════════════════════════════════════════════════════════════════
// СТАТИСТИКА МЕНЕДЖЕРОВ ПО МЕСЯЦАМ
// ═══════════════════════════════════════════════════════════════════
var _MONTHLY_STATS = [
{id:'ak', name:'Анна К.', color:'#7C3AED', salon:'lenina', months:{
'Май':{visits:42, deals:14, revenue:847000, conversion:33, avg:60500, rating:4.8},
'Апр':{visits:38, deals:11, revenue:712000, conversion:29, avg:64700, rating:4.7},
'Мар':{visits:45, deals:16, revenue:920000, conversion:36, avg:57500, rating:4.9},
}},
{id:'ms', name:'Мария С.', color:'#0891B2', salon:'lenina', months:{
'Май':{visits:35, deals:9, revenue:610000, conversion:26, avg:67800, rating:4.5},
'Апр':{visits:41, deals:13, revenue:780000, conversion:32, avg:60000, rating:4.6},
'Мар':{visits:39, deals:12, revenue:695000, conversion:31, avg:57900, rating:4.4},
}},
{id:'pv', name:'Пётр В.', color:'#059669', salon:'pobedy', months:{
'Май':{visits:28, deals:7, revenue:490000, conversion:25, avg:70000, rating:4.3},
'Апр':{visits:32, deals:9, revenue:540000, conversion:28, avg:60000, rating:4.2},
'Мар':{visits:30, deals:8, revenue:520000, conversion:27, avg:65000, rating:4.4},
}},
{id:'iv', name:'Иван В.', color:'#D97706', salon:'pobedy', months:{
'Май':{visits:31, deals:8, revenue:530000, conversion:26, avg:66250, rating:4.1},
'Апр':{visits:29, deals:7, revenue:480000, conversion:24, avg:68600, rating:4.0},
'Мар':{visits:33, deals:10, revenue:610000, conversion:30, avg:61000, rating:4.3},
}},
];
// ═══════════════════════════════════════════════════════════════════
// ЗАЯВКИ МЕНЕДЖЕРОВ → АДМИНИСТРАТОР (+ эскалация → КД)
// ═══════════════════════════════════════════════════════════════════
window._MGR_REQUESTS = window._MGR_REQUESTS || [
{id:'r1', mgr:'Анна К.', mgrId:'ak', salon:'lenina', color:'#7C3AED', type:'supply', prio:'high', title:'Закончились образцы ткани', body:'Нет образцов искусственной замши — теряем клиентов. Нужно срочно дозаказать у Мебельтекстиля.', created:'сегодня 09:14', status:'new'},
{id:'r2', mgr:'Мария С.', mgrId:'ms', salon:'lenina', color:'#0891B2', type:'escalate', prio:'high', title:'Конфликт с клиентом Козлов Р.', body:'Клиент требует возврат 25 000 ₽ из-за задержки поставки. Говорит, что подаст жалобу. Прошу вмешаться.', created:'сегодня 10:30', status:'new'},
{id:'r3', mgr:'Пётр В.', mgrId:'pv', salon:'pobedy', color:'#059669', type:'visit', prio:'normal', title:'Нужна машина для выезда к клиенту', body:'Клиент Сидорова на Васильевском — хочет видеть образцы на дому. Нужен транспорт на 15:00.', created:'сегодня 11:05', status:'new'},
{id:'r4', mgr:'Анна К.', mgrId:'ak', salon:'lenina', color:'#7C3AED', type:'supply', prio:'normal', title:'Каталоги кухонь Hettich закончились', body:'Остался 1 экземпляр. Клиенты берут домой, не возвращают. Надо заказать 10 шт.', created:'вчера 17:22', status:'done'},
{id:'r5', mgr:'Мария С.', mgrId:'ms', salon:'lenina', color:'#0891B2', type:'schedule', prio:'normal', title:'Запрос на замену смены — 31 мая', body:'Прошу разрешить обменяться сменой с Петром: я работаю 31 мая вместо него, он — 1 июня вместо меня.', created:'вчера 14:10', status:'new'},
];
// ═══════════════════════════════════════════════════════════════════
// ЗАПРОСЫ НА СМЕНЫ
// ═══════════════════════════════════════════════════════════════════
window._SHIFT_REQS = window._SHIFT_REQS || [
{id:'sr1', mgr:'Мария С.', mgrId:'ms', salon:'lenina', color:'#0891B2', type:'swap', dates:'31 мая ↔ 1 июня', with:'Пётр В.', status:'pending'},
{id:'sr2', mgr:'Пётр В.', mgrId:'pv', salon:'pobedy', color:'#059669', type:'off', dates:'2 июня (отгул)', with:null, status:'pending'},
];
// ═══════════════════════════════════════════════════════════════════
// ХЕЛПЕРЫ — утилиты доступные всем кабинетам
// ═══════════════════════════════════════════════════════════════════
/** Найти запись _HIERARCHY по salonId */
function _getSalon(salonId){
return _HIERARCHY.find(function(h){ return h.salonId===salonId; }) || null;
}
/** Найти менеджера по id из плоского списка */
function _getMgr(mgrId){
return _CHESS_MGRS.find(function(m){ return m.id===mgrId; }) || null;
}
/** Получить KPI менеджера за период (из _MONTHLY_STATS) */
function _getMgrStats(mgrId, period){
var stat = _MONTHLY_STATS.find(function(s){ return s.id===mgrId; });
return stat ? (stat.months[period||'Май'] || {}) : {};
}