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}
-
-
-
-
-
-
-
- `).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 ''
+ +'
'
+ +'
'+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 ''
+ +'
'
+ +'
'+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'