diff --git a/docs/mockup_director.html b/docs/mockup_director.html index 0e35bd6..b314e19 100644 --- a/docs/mockup_director.html +++ b/docs/mockup_director.html @@ -234,6 +234,8 @@ const SCREENS = { analytics: 'Аналитика', profile: 'Профиль', staff_edit: 'Редактирование сотрудника', + staff_new: 'Новый сотрудник', + staff_cat_confirm: 'Подтверждение категории', settings: 'Настройки' }; @@ -340,6 +342,8 @@ function renderScreen(id) { case 'staff_block_confirm':return screenStaffBlockConfirm(); case 'staff_blocked': return screenStaffBlocked(); case 'staff_edit': return screenStaffEdit(); + case 'staff_new': return screenStaffNew(); + case 'staff_cat_confirm': return screenStaffCatConfirm(); case 'assemblies': return screenAssemblies(); case 'assembly_detail': return screenAssemblyDetail(); case 'pricelist': return screenPricelist(); @@ -883,58 +887,88 @@ function screenHome() { // ── SCREEN 2: STAFF ────────────────────────────────────────── function screenStaff() { - const employees = [ - {init:'КА',name:'Кириллов А.В.',role:'Сборщик',badge:'blue',active:true,sub:'Сборок в мае: 18 · Рейтинг: 4.8 ⭐'}, - {init:'ПС',name:'Петров С.И.',role:'Сборщик',badge:'blue',active:true,sub:'Сборок в мае: 14 · Рейтинг: 4.9 ⭐'}, - {init:'СО',name:'Смирнов О.К.',role:'Сборщик',badge:'blue',active:true,sub:'Сборок в мае: 11 · Рейтинг: 4.7 ⭐'}, - {init:'ФМ',name:'Фёдорова М.Р.',role:'Замерщик',badge:'purple',active:true,sub:'Замеров: 12 · Рейтинг: 4.8 ⭐'}, - {init:'НП',name:'Николаев П.В.',role:'Сборщик',badge:'yellow',active:false,sub:'Сборок в мае: 3 · Рейтинг: 4.2 ⭐'}, - {init:'КД',name:'Кузнецова А.Д.',role:'Менеджер',badge:'green',active:true,sub:'Клиентов: 8 · Рейтинг: 4.9 ⭐'}, + // Workload data — сортировка: Кат.А выше Кат.Б + var emps = [ + {init:'КА',name:'Кириллов А.В.', role:'Сборщик', cat:'A', load:85, jobs:3, rating:4.8, badge:'blue', active:true}, + {init:'ПС',name:'Петров С.И.', role:'Сборщик', cat:'A', load:72, jobs:2, rating:4.9, badge:'blue', active:true}, + {init:'ФМ',name:'Фёдорова М.Р.',role:'Замерщик', cat:'A', load:79, jobs:2, rating:4.8, badge:'purple', active:true}, + {init:'СО',name:'Смирнов О.К.', role:'Сборщик', cat:'B', load:68, jobs:2, rating:4.7, badge:'blue', active:true}, + {init:'НП',name:'Николаев П.В.',role:'Сборщик', cat:'B', load:40, jobs:1, rating:4.2, badge:'yellow', active:false}, + {init:'КД',name:'Кузнецова А.Д.',role:'Менеджер',cat:null,load:null,jobs:4,rating:4.9, badge:'green', active:true}, ]; - return `
- - -
-
Все
-
Сборщики
-
Замерщики
-
Менеджеры
-
-
- ${employees.map(e => ` -
-
-
-
${e.init}
-
-
- ${e.name} - ${e.role} -
-
-
- ${e.sub} -
-
-
- -
-
- `).join('')} -
- ${navBar('staff')} -
`; + // Business rule: avg load Cat A >= avg load Cat B (for assemblers only) + var asmA = emps.filter(function(e){return e.role==='Сборщик'&&e.cat==='A';}); + var asmB = emps.filter(function(e){return e.role==='Сборщик'&&e.cat==='B';}); + var avgA = asmA.reduce(function(s,e){return s+e.load;},0)/asmA.length; + var avgB = asmB.reduce(function(s,e){return s+e.load;},0)/asmB.length; + var loadWarn = avgA < avgB; + + function catBadge(cat) { + if (!cat) return ''; + var col = cat==='A' ? '#4338CA' : '#D97706'; + var bg = cat==='A' ? 'rgba(99,102,241,.1)' : 'rgba(245,158,11,.1)'; + return 'Кат.'+cat+''; + } + function loadBar(pct, active) { + if (pct===null) return ''; + var col = pct>=75 ? 'var(--success)' : pct>=50 ? 'var(--accent)' : 'var(--warn)'; + if (!active) col='var(--muted)'; + return '
' + +'
' + +'Загрузка' + +''+pct+'%' + +'
' + +'
' + +'
' + +'
' + +'
'; + } + + var warnBanner = loadWarn + ? '
' + +'⚠️ Нарушение правила загрузки: Кат.Б перегружена относительно Кат.А. Перераспределите заказы.' + +'
' + : ''; + + var cards = emps.map(function(e) { + return '
' + +'
' + +'
' + e.init + '
' + +'
' + +'
' + +'' + e.name + '' + +'' + e.role + '' + + catBadge(e.cat) + +'
' + +'
' + +'
' + +'' + (e.active?'Онлайн':'Не активен') + ' · ' + e.jobs + (e.role==='Менеджер'?' клиентов':' заказ.' ) + ' сегодня · ⭐ ' + e.rating + '' + +'
' + + loadBar(e.load, e.active) + +'
' + +'' + +'
' + +'
'; + }).join(''); + + return '
' + +'' + +'' + +'
' + +'
Все
' + +'
Сборщики
' + +'
Замерщики
' + +'
Менеджеры
' + +'
' + + warnBanner + +'
' + cards + '
' + + navBar('staff') + +'
'; } // ── SCREEN 3: STAFF DETAIL ──────────────────────────────────── @@ -955,8 +989,36 @@ function screenStaffDetail() {
Кириллов Алексей Владимирович
Сборщик + Кат.А ● Активен
+
В системе с 12.03.2025 · Стаж: 14 мес.
+ + + +
+
Категория и загрузка
+
+
+
Кат.А
+
Подтверждена 15.04.2026
+
+ +
+
+ ● Допуск на любые объекты, включая премиальные
+ ● Самостоятельная работа без куратора
+ ● Полная материальная ответственность +
+
Загрузка сегодня
+
+ 3 из 4 слотов занято + 85% +
+
+
+
+
Правило: Кат.А ≥ Кат.Б · Средняя загрузка Кат.Б: 54% ✓
@@ -1199,6 +1261,259 @@ function screenStaffEdit() { + ''; } + +// ── SCREEN 3c: NEW EMPLOYEE QUESTIONNAIRE ───────────────────── +function screenStaffNew() { + if (window._newStep === undefined) window._newStep = 1; + if (window._newRole === undefined) window._newRole = {asm:true, meas:false}; + if (window._newExp === undefined) window._newExp = null; // 'new'|'1-2'|'3+' + if (window._newFurn === undefined) window._newFurn = {corpus:false, upholstered:false, kitchen:false, office:false, premium:false}; + if (window._newCar === undefined) window._newCar = null; // true|false + if (window._newArea === undefined) window._newArea = {center:false, north:false, south:false, east:false, west:false}; + + var step = window._newStep; + + function roleBtn(key, label) { + var on = window._newRole[key]; + return ''; + } + function expBtn(val, label) { + var on = window._newExp===val; + return ''; + } + function chk(key, obj, screen, label) { + var on = window[obj][key]; + return '
' + +'
' + +(on?'':'') + +'
' + +''+label+'' + +'
'; + } + function carBtn(val, label, icon) { + var on = window._newCar===val; + return ''; + } + function areaChk(key, label) { + return chk(key, '_newArea', 'staff_new', label); + } + + var stepDots = '
'; + for (var s=1; s<=3; s++) { + stepDots += '
'; + } + stepDots += '
'; + + var body = ''; + if (step===1) { + body = '
' + +'
Шаг 1 из 3 — Базовая информация
' + +'
Кто новый сотрудник?
' + +'
' + +'
ФИО
' + +'' + +'
Телефон
' + +'' + +'
Telegram
' + +'' + +'
Роль
' + +'
' + roleBtn('asm','Сборщик') + roleBtn('meas','Замерщик') + '
' + +'
' + +'' + +'
'; + } else if (step===2) { + body = '
' + +'
Шаг 2 из 3 — Квалификация
' + +'
Опыт и навыки
' + +'
' + +'
Опыт в сборке мебели
' + +'
' + + expBtn('new','Нет опыта') + expBtn('1-2','1–2 года') + expBtn('3+','3+ лет') + +'
' + +'
Типы мебели
' + +'
Отметьте с чем работал
' + + chk('corpus','_newFurn','staff_new','Корпусная (шкафы, стеллажи, комоды)') + + chk('upholstered','_newFurn','staff_new','Мягкая (диваны, кресла)') + + chk('kitchen','_newFurn','staff_new','Кухонные гарнитуры') + + chk('office','_newFurn','staff_new','Офисная мебель') + + chk('premium','_newFurn','staff_new','Премиальная / итальянская') + +'
' + +'
' + +'
Прежнее место работы
' + +'' + +'
' + +'
' + +'' + +'' + +'
' + +'
'; + } else { + body = '
' + +'
Шаг 3 из 3 — Логистика
' + +'
Транспорт и зона работы
' + +'
' + +'
Личный автомобиль
' + +'
' + + carBtn('true','Есть авто','🚗') + carBtn('false','Без авто','🚌') + +'
' + +'
' + +'
' + +'
Зона работы
' + +'
Комфортные районы города
' + + areaChk('center','Центр города') + + areaChk('north','Север') + + areaChk('south','Юг') + + areaChk('east','Восток') + + areaChk('west','Запад / ЗАД') + +'
' + +'
' + +'После заполнения анкеты вы сможете назначить категорию на основе ответов.' + +'
' + +'
' + +'' + +'' + +'
' + +'
'; + } + + return '
' + +'' + + stepDots + + body + + navBar('staff') + +'
'; +} + +// ── SCREEN 3d: CATEGORY CONFIRMATION ────────────────────────── +function screenStaffCatConfirm() { + if (window._confirmCat === undefined) window._confirmCat = null; // 'A'|'B' + if (window._confirmRate === undefined) window._confirmRate = 2500; + if (window._confirmSlots === undefined) window._confirmSlots = 3; + if (window._confirmProb === undefined) window._confirmProb = 4; // weeks + if (window._confirmFurnA === undefined) window._confirmFurnA = {corpus:true,kitchen:true,office:true,upholstered:false,premium:false}; + if (window._confirmFurnB === undefined) window._confirmFurnB = {corpus:true,kitchen:false,office:true,upholstered:false,premium:false}; + + function catBtn2(val, title, desc, col) { + var on = window._confirmCat===val; + return ''; + } + function counter(key, label, min, max) { + var val = window[key]; + return '
' + +''+label+'' + +'
' + +'' + +''+val+'' + +'' + +'
' + +'
'; + } + function furnChk(key, label) { + var obj = window._confirmCat==='B' ? '_confirmFurnB' : '_confirmFurnA'; + var on = window[obj][key]; + return '
' + +'
' + +(on?'':'') + +'
' + +''+label+'' + +'
'; + } + + // Recommendation engine based on questionnaire + var score = 0; + if (window._newFurn && window._newFurn.premium) score += 3; + if (window._newFurn && window._newFurn.kitchen) score += 2; + if (window._newExp === '3+') score += 3; + if (window._newExp === '1-2') score += 1; + if (window._newCar === true || window._newCar === 'true') score += 1; + var recommended = score >= 4 ? 'A' : 'B'; + + var catSection = '
' + +'
Назначить категорию
' + +'
' + +'💡 Рекомендация системы: Кат.'+recommended+' на основе анкеты' + +'
' + +'
' + + catBtn2('A','Категория А','Премиальные объекты · Самостоятельная работа · Повышенная ставка','#4338CA') + + catBtn2('B','Категория Б','Стандартные объекты · Куратор при необходимости · Базовая ставка','#D97706') + +'
' + +(window._confirmCat===null ? '
Выберите категорию для продолжения
' : '') + +'
'; + + var paramsSection = window._confirmCat===null ? '' : ( + '
' + +'
Параметры
' + + counter('_confirmRate','Ставка за сборку, ₽',1000,5000) + + counter('_confirmSlots','Макс. заказов в день',1,6) + + counter('_confirmProb','Испытательный срок, нед.',1,12) + +'
' + +'
' + +'
Допустимые типы мебели
' + +'
'+(window._confirmCat==='A'?'Кат.А — полный доступ, снимите галку для запрета':'Кат.Б — ограниченный доступ, отметьте разрешённое')+'
' + + furnChk('corpus', 'Корпусная (шкафы, комоды, стеллажи)') + + furnChk('kitchen', 'Кухонные гарнитуры') + + furnChk('office', 'Офисная мебель') + + furnChk('upholstered','Мягкая мебель (диваны, кресла)') + + furnChk('premium', 'Премиальная / итальянская') + +'
' + +'
' + +'
Примечание директора
' + +'' + +'
' + +'' + ); + + return '
' + +'' + +'
' + + catSection + + paramsSection + +'
' + + navBar('staff') + +'
'; +} + // ── SCREEN 4: STAFF BLOCK CONFIRM ───────────────────────────── function screenStaffBlockConfirm() { // Роль сотрудника — в реале берётся из профиля, здесь симулируем: 'asm'|'meas'|'both'