mirror of
https://github.com/wasrusgen/wasrusgen1-crm.git
synced 2026-06-03 19:04:47 +00:00
feat: director — assembler categories, workload bars, new employee questionnaire, category confirmation
This commit is contained in:
parent
9e9c3c8369
commit
bbac7aed93
@ -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 `<div class="page">
|
||||
<div class="page-header">
|
||||
<h2 style="display:flex;align-items:center;gap:7px">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 18a1 1 0 001 1h18a1 1 0 001-1v-2a1 1 0 00-1-1H3a1 1 0 00-1 1v2z"/><path d="M10 10V5a1 1 0 011-1h2a1 1 0 011 1v5"/><path d="M4 15v-3a8 8 0 018-8"/><path d="M20 15v-3a8 8 0 00-8-8"/></svg>
|
||||
Сборщики
|
||||
</h2>
|
||||
<button class="header-action">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="search-bar">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
|
||||
<input type="text" placeholder="Поиск по имени, роли...">
|
||||
</div>
|
||||
<div class="chip-row" style="padding:0 16px;margin-bottom:12px">
|
||||
<div class="chip active">Все</div>
|
||||
<div class="chip">Сборщики</div>
|
||||
<div class="chip">Замерщики</div>
|
||||
<div class="chip">Менеджеры</div>
|
||||
</div>
|
||||
<div style="padding:0 16px">
|
||||
${employees.map(e => `
|
||||
<div class="card" onclick="navigate('staff_detail')" style="cursor:pointer;padding:12px 14px;margin-bottom:8px">
|
||||
<div class="row sb">
|
||||
<div class="row" style="gap:12px;flex:1">
|
||||
<div class="avatar" style="background:var(--accent)">${e.init}</div>
|
||||
<div class="col" style="flex:1">
|
||||
<div class="row" style="gap:6px">
|
||||
<span style="font-size:14px;font-weight:700;color:var(--ink)">${e.name}</span>
|
||||
<span class="badge ${e.badge}" style="font-size:10px;padding:2px 8px">${e.role}</span>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:6px;margin-top:4px">
|
||||
<div style="width:8px;height:8px;border-radius:50%;background:${e.active ? 'var(--success)' : 'var(--warn)'};flex-shrink:0"></div>
|
||||
<span style="font-size:12px;color:var(--muted)">${e.sub}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="color:var(--muted);flex-shrink:0"><polyline points="9 18 15 12 9 6"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
${navBar('staff')}
|
||||
</div>`;
|
||||
// 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 '<span style="font-size:10px;font-weight:800;padding:2px 7px;border-radius:20px;background:'+bg+';color:'+col+'">Кат.'+cat+'</span>';
|
||||
}
|
||||
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 '<div style="margin-top:7px">'
|
||||
+'<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:3px">'
|
||||
+'<span style="font-size:10px;color:var(--muted);font-weight:500">Загрузка</span>'
|
||||
+'<span style="font-size:11px;font-weight:800;color:'+col+'">'+pct+'%</span>'
|
||||
+'</div>'
|
||||
+'<div style="height:4px;background:rgba(0,0,0,.07);border-radius:2px;overflow:hidden">'
|
||||
+'<div style="height:100%;width:'+pct+'%;background:'+col+';border-radius:2px;transition:width .4s"></div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
}
|
||||
|
||||
var warnBanner = loadWarn
|
||||
? '<div style="margin:0 16px 10px;padding:10px 12px;background:rgba(239,68,68,.08);border:1px solid rgba(239,68,68,.25);border-radius:10px;font-size:12px;color:#B91C1C;font-weight:600">'
|
||||
+'<span style="font-size:14px">⚠️</span> Нарушение правила загрузки: Кат.Б перегружена относительно Кат.А. Перераспределите заказы.'
|
||||
+'</div>'
|
||||
: '';
|
||||
|
||||
var cards = emps.map(function(e) {
|
||||
return '<div class="card" onclick="navigate(\'staff_detail\')" style="cursor:pointer;padding:12px 14px;margin-bottom:8px">'
|
||||
+'<div style="display:flex;align-items:flex-start;gap:12px">'
|
||||
+'<div class="avatar" style="background:var(--accent);flex-shrink:0">' + e.init + '</div>'
|
||||
+'<div style="flex:1;min-width:0">'
|
||||
+'<div style="display:flex;align-items:center;gap:6px;flex-wrap:wrap">'
|
||||
+'<span style="font-size:14px;font-weight:700;color:var(--ink)">' + e.name + '</span>'
|
||||
+'<span class="badge ' + e.badge + '" style="font-size:10px;padding:2px 8px">' + e.role + '</span>'
|
||||
+ catBadge(e.cat)
|
||||
+'</div>'
|
||||
+'<div style="display:flex;align-items:center;gap:6px;margin-top:4px">'
|
||||
+'<div style="width:7px;height:7px;border-radius:50%;background:' + (e.active?'var(--success)':'var(--muted)') + ';flex-shrink:0"></div>'
|
||||
+'<span style="font-size:12px;color:var(--muted)">' + (e.active?'Онлайн':'Не активен') + ' · ' + e.jobs + (e.role==='Менеджер'?' клиентов':' заказ.' ) + ' сегодня · ⭐ ' + e.rating + '</span>'
|
||||
+'</div>'
|
||||
+ loadBar(e.load, e.active)
|
||||
+'</div>'
|
||||
+'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="color:var(--muted);flex-shrink:0;margin-top:3px"><polyline points="9 18 15 12 9 6"/></svg>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
}).join('');
|
||||
|
||||
return '<div class="page">'
|
||||
+'<div class="page-header">'
|
||||
+'<h2>Команда</h2>'
|
||||
+'<button class="header-action" onclick="navigate(\'staff_new\')">'
|
||||
+'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>'
|
||||
+'</button>'
|
||||
+'</div>'
|
||||
+'<div class="search-bar"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg><input type="text" placeholder="Поиск по имени, роли..."></div>'
|
||||
+'<div class="chip-row" style="padding:0 16px;margin-bottom:10px">'
|
||||
+'<div class="chip active">Все</div>'
|
||||
+'<div class="chip">Сборщики</div>'
|
||||
+'<div class="chip">Замерщики</div>'
|
||||
+'<div class="chip">Менеджеры</div>'
|
||||
+'</div>'
|
||||
+ warnBanner
|
||||
+'<div style="padding:0 16px">' + cards + '</div>'
|
||||
+ navBar('staff')
|
||||
+'</div>';
|
||||
}
|
||||
|
||||
// ── SCREEN 3: STAFF DETAIL ────────────────────────────────────
|
||||
@ -955,8 +989,36 @@ function screenStaffDetail() {
|
||||
<div style="font-size:19px;font-weight:800;color:var(--ink)">Кириллов Алексей Владимирович</div>
|
||||
<div style="margin-top:8px;display:flex;align-items:center;justify-content:center;gap:8px">
|
||||
<span class="badge blue">Сборщик</span>
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;background:rgba(99,102,241,.1);color:#4338CA;border-radius:20px;padding:3px 10px;font-size:11px;font-weight:800">Кат.А</span>
|
||||
<span style="display:inline-flex;align-items:center;gap:4px;background:#DCFCE7;color:#15803D;border-radius:20px;padding:3px 10px;font-size:11px;font-weight:700">● Активен</span>
|
||||
</div>
|
||||
<div style="margin-top:6px;font-size:12px;color:var(--muted)">В системе с 12.03.2025 · Стаж: 14 мес.</div>
|
||||
</div>
|
||||
|
||||
<!-- Category & Workload -->
|
||||
<div class="card" style="padding:14px 16px">
|
||||
<div style="font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:12px">Категория и загрузка</div>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:10px">
|
||||
<div>
|
||||
<div style="font-size:22px;font-weight:900;color:#4338CA">Кат.А</div>
|
||||
<div style="font-size:11px;color:var(--muted);margin-top:2px">Подтверждена 15.04.2026</div>
|
||||
</div>
|
||||
<button onclick="navigate('staff_cat_confirm')" style="background:rgba(99,102,241,.1);color:#4338CA;border:1.5px solid rgba(99,102,241,.3);border-radius:10px;padding:8px 14px;font-size:12px;font-weight:700;cursor:pointer">Пересмотреть</button>
|
||||
</div>
|
||||
<div style="padding:8px 10px;background:rgba(99,102,241,.06);border-radius:8px;font-size:11px;color:#4338CA;line-height:1.6;margin-bottom:14px">
|
||||
● Допуск на любые объекты, включая премиальные<br>
|
||||
● Самостоятельная работа без куратора<br>
|
||||
● Полная материальная ответственность
|
||||
</div>
|
||||
<div style="font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px">Загрузка сегодня</div>
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:5px">
|
||||
<span style="font-size:13px;color:var(--ink);font-weight:600">3 из 4 слотов занято</span>
|
||||
<span style="font-size:16px;font-weight:900;color:var(--success)">85%</span>
|
||||
</div>
|
||||
<div style="height:8px;background:rgba(0,0,0,.06);border-radius:4px;overflow:hidden;margin-bottom:6px">
|
||||
<div style="height:100%;width:85%;background:var(--success);border-radius:4px"></div>
|
||||
</div>
|
||||
<div style="font-size:11px;color:var(--muted)">Правило: Кат.А ≥ Кат.Б · Средняя загрузка Кат.Б: 54% ✓</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact -->
|
||||
@ -1199,6 +1261,259 @@ function screenStaffEdit() {
|
||||
+ '</div>';
|
||||
}
|
||||
|
||||
|
||||
// ── 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 '<button onclick="(function(){window._newRole[\'' + key + '\']=!window._newRole[\'' + key + '\'];'
|
||||
+'document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="flex:1;padding:11px 4px;font-size:13px;font-weight:700;border-radius:10px;cursor:pointer;border:1.5px solid '
|
||||
+(on?'var(--accent)':'rgba(0,0,0,.12)')+';background:'+(on?'rgba(0,62,126,.08)':'transparent')+';color:'+(on?'var(--accent)':'var(--muted)')+';">'
|
||||
+(on?'✓ ':'')+label+'</button>';
|
||||
}
|
||||
function expBtn(val, label) {
|
||||
var on = window._newExp===val;
|
||||
return '<button onclick="(function(){window._newExp=\'' + val + '\';'
|
||||
+'document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="flex:1;padding:9px 4px;font-size:12px;font-weight:700;border-radius:10px;cursor:pointer;border:1.5px solid '
|
||||
+(on?'var(--accent)':'rgba(0,0,0,.12)')+';background:'+(on?'rgba(0,62,126,.08)':'transparent')+';color:'+(on?'var(--accent)':'var(--muted)')+';">'
|
||||
+label+'</button>';
|
||||
}
|
||||
function chk(key, obj, screen, label) {
|
||||
var on = window[obj][key];
|
||||
return '<div onclick="(function(){window[\''+obj+'\'][\''+key+'\']=!window[\''+obj+'\'][\''+key+'\'];'
|
||||
+'document.getElementById(\'screen\').innerHTML=renderScreen(\''+screen+'\')})();"'
|
||||
+' style="display:flex;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.05);cursor:pointer">'
|
||||
+'<div style="width:22px;height:22px;border-radius:6px;border:1.5px solid '+(on?'var(--accent)':'rgba(0,0,0,.15)')+';background:'+(on?'var(--accent)':'transparent')+';display:flex;align-items:center;justify-content:center;flex-shrink:0">'
|
||||
+(on?'<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg>':'')
|
||||
+'</div>'
|
||||
+'<span style="font-size:13px;color:'+(on?'var(--ink)':'var(--muted)')+';font-weight:'+(on?'600':'400')+'">'+label+'</span>'
|
||||
+'</div>';
|
||||
}
|
||||
function carBtn(val, label, icon) {
|
||||
var on = window._newCar===val;
|
||||
return '<button onclick="(function(){window._newCar='+val+';'
|
||||
+'document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="flex:1;padding:14px 4px;font-size:12px;font-weight:700;border-radius:10px;cursor:pointer;border:1.5px solid '
|
||||
+(on?'var(--accent)':'rgba(0,0,0,.12)')+';background:'+(on?'rgba(0,62,126,.08)':'transparent')+';color:'+(on?'var(--accent)':'var(--muted)')+';">'
|
||||
+icon+'<br>'+label+'</button>';
|
||||
}
|
||||
function areaChk(key, label) {
|
||||
return chk(key, '_newArea', 'staff_new', label);
|
||||
}
|
||||
|
||||
var stepDots = '<div style="display:flex;gap:6px;justify-content:center;padding:14px 16px 0">';
|
||||
for (var s=1; s<=3; s++) {
|
||||
stepDots += '<div style="height:4px;flex:1;border-radius:2px;background:'+(s===step?'var(--accent)':s<step?'var(--success)':'rgba(0,0,0,.12)')+'"></div>';
|
||||
}
|
||||
stepDots += '</div>';
|
||||
|
||||
var body = '';
|
||||
if (step===1) {
|
||||
body = '<div style="padding:16px">'
|
||||
+'<div style="font-size:13px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px">Шаг 1 из 3 — Базовая информация</div>'
|
||||
+'<div style="font-size:19px;font-weight:800;color:var(--ink);margin-bottom:16px">Кто новый сотрудник?</div>'
|
||||
+'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">ФИО</div>'
|
||||
+'<input type="text" placeholder="Иванов Иван Иванович" style="width:100%;padding:10px 12px;border:1.5px solid rgba(0,0,0,.12);border-radius:10px;font-size:14px;color:var(--ink);background:var(--bg);outline:none;margin-bottom:14px">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">Телефон</div>'
|
||||
+'<input type="tel" placeholder="+7 900 000-00-00" style="width:100%;padding:10px 12px;border:1.5px solid rgba(0,0,0,.12);border-radius:10px;font-size:14px;color:var(--ink);background:var(--bg);outline:none;margin-bottom:14px">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">Telegram</div>'
|
||||
+'<input type="text" placeholder="@username" style="width:100%;padding:10px 12px;border:1.5px solid rgba(0,0,0,.12);border-radius:10px;font-size:14px;color:var(--ink);background:var(--bg);outline:none;margin-bottom:14px">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">Роль</div>'
|
||||
+'<div style="display:flex;gap:8px">' + roleBtn('asm','Сборщик') + roleBtn('meas','Замерщик') + '</div>'
|
||||
+'</div>'
|
||||
+'<button onclick="(function(){window._newStep=2;document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="width:100%;padding:14px;background:var(--accent);color:#fff;border:none;border-radius:12px;font-size:15px;font-weight:700;cursor:pointer;margin-top:4px">Далее →</button>'
|
||||
+'</div>';
|
||||
} else if (step===2) {
|
||||
body = '<div style="padding:16px">'
|
||||
+'<div style="font-size:13px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px">Шаг 2 из 3 — Квалификация</div>'
|
||||
+'<div style="font-size:19px;font-weight:800;color:var(--ink);margin-bottom:16px">Опыт и навыки</div>'
|
||||
+'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">Опыт в сборке мебели</div>'
|
||||
+'<div style="display:flex;gap:8px;margin-bottom:14px">'
|
||||
+ expBtn('new','Нет опыта') + expBtn('1-2','1–2 года') + expBtn('3+','3+ лет')
|
||||
+'</div>'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:2px">Типы мебели</div>'
|
||||
+'<div style="font-size:11px;color:var(--muted);margin-bottom:8px">Отметьте с чем работал</div>'
|
||||
+ 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','Премиальная / итальянская')
|
||||
+'</div>'
|
||||
+'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">Прежнее место работы</div>'
|
||||
+'<input type="text" placeholder="ИКЕА, Hoff, Свой сборщик..." style="width:100%;padding:10px 12px;border:1.5px solid rgba(0,0,0,.12);border-radius:10px;font-size:14px;color:var(--ink);background:var(--bg);outline:none">'
|
||||
+'</div>'
|
||||
+'<div style="display:flex;gap:8px;margin-top:4px">'
|
||||
+'<button onclick="(function(){window._newStep=1;document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="flex:1;padding:14px;background:transparent;color:var(--accent);border:1.5px solid var(--accent);border-radius:12px;font-size:14px;font-weight:700;cursor:pointer">← Назад</button>'
|
||||
+'<button onclick="(function(){window._newStep=3;document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="flex:2;padding:14px;background:var(--accent);color:#fff;border:none;border-radius:12px;font-size:14px;font-weight:700;cursor:pointer">Далее →</button>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
} else {
|
||||
body = '<div style="padding:16px">'
|
||||
+'<div style="font-size:13px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px">Шаг 3 из 3 — Логистика</div>'
|
||||
+'<div style="font-size:19px;font-weight:800;color:var(--ink);margin-bottom:16px">Транспорт и зона работы</div>'
|
||||
+'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px">Личный автомобиль</div>'
|
||||
+'<div style="display:flex;gap:8px;margin-bottom:4px">'
|
||||
+ carBtn('true','Есть авто','🚗') + carBtn('false','Без авто','🚌')
|
||||
+'</div>'
|
||||
+'</div>'
|
||||
+'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);margin-bottom:2px">Зона работы</div>'
|
||||
+'<div style="font-size:11px;color:var(--muted);margin-bottom:8px">Комфортные районы города</div>'
|
||||
+ areaChk('center','Центр города')
|
||||
+ areaChk('north','Север')
|
||||
+ areaChk('south','Юг')
|
||||
+ areaChk('east','Восток')
|
||||
+ areaChk('west','Запад / ЗАД')
|
||||
+'</div>'
|
||||
+'<div style="padding:10px 12px;background:rgba(118,189,34,.08);border:1px solid rgba(118,189,34,.3);border-radius:10px;font-size:12px;color:#4D7C0F;font-weight:500;margin-bottom:4px">'
|
||||
+'После заполнения анкеты вы сможете назначить категорию на основе ответов.'
|
||||
+'</div>'
|
||||
+'<div style="display:flex;gap:8px;margin-top:4px">'
|
||||
+'<button onclick="(function(){window._newStep=2;document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_new\')})()"'
|
||||
+' style="flex:1;padding:14px;background:transparent;color:var(--accent);border:1.5px solid var(--accent);border-radius:12px;font-size:14px;font-weight:700;cursor:pointer">← Назад</button>'
|
||||
+'<button onclick="navigate(\'staff_cat_confirm\')"'
|
||||
+' style="flex:2;padding:14px;background:var(--success);color:#fff;border:none;border-radius:12px;font-size:14px;font-weight:700;cursor:pointer">Назначить категорию →</button>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
}
|
||||
|
||||
return '<div class="page">'
|
||||
+'<div class="page-header">'
|
||||
+'<button class="back-btn" onclick="navigate(\'staff\')">'
|
||||
+'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="15 18 9 12 15 6"/></svg>'
|
||||
+'</button>'
|
||||
+'<h2>Новый сотрудник</h2>'
|
||||
+'</div>'
|
||||
+ stepDots
|
||||
+ body
|
||||
+ navBar('staff')
|
||||
+'</div>';
|
||||
}
|
||||
|
||||
// ── 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 '<button onclick="(function(){window._confirmCat=\''+val+'\';'
|
||||
+'document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_cat_confirm\')})()"'
|
||||
+' style="flex:1;padding:14px 10px;border-radius:12px;cursor:pointer;border:2px solid '
|
||||
+(on?col:'rgba(0,0,0,.1)')+';background:'+(on?col+'18':'transparent')+';text-align:left">'
|
||||
+'<div style="font-size:18px;font-weight:900;color:'+(on?col:'var(--muted)')+';margin-bottom:4px">Кат.'+val+'</div>'
|
||||
+'<div style="font-size:11px;color:'+(on?col:'var(--muted)')+';line-height:1.4">'+desc+'</div>'
|
||||
+'</button>';
|
||||
}
|
||||
function counter(key, label, min, max) {
|
||||
var val = window[key];
|
||||
return '<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 0;border-bottom:1px solid rgba(0,0,0,.05)">'
|
||||
+'<span style="font-size:13px;color:var(--ink)">'+label+'</span>'
|
||||
+'<div style="display:flex;align-items:center;gap:12px">'
|
||||
+'<button onclick="(function(){if(window[\''+key+'\']>'+min+')window[\''+key+'\']-=1;document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_cat_confirm\')})()"'
|
||||
+' style="width:28px;height:28px;border-radius:8px;background:rgba(0,0,0,.07);border:none;font-size:16px;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--ink)">−</button>'
|
||||
+'<span style="font-size:16px;font-weight:800;color:var(--accent);min-width:24px;text-align:center">'+val+'</span>'
|
||||
+'<button onclick="(function(){if(window[\''+key+'\']<'+max+')window[\''+key+'\']+= 1;document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_cat_confirm\')})()"'
|
||||
+' style="width:28px;height:28px;border-radius:8px;background:rgba(0,0,0,.07);border:none;font-size:16px;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--ink)">+</button>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
}
|
||||
function furnChk(key, label) {
|
||||
var obj = window._confirmCat==='B' ? '_confirmFurnB' : '_confirmFurnA';
|
||||
var on = window[obj][key];
|
||||
return '<div onclick="(function(){window[\''+obj+'\'][\''+key+'\']=!window[\''+obj+'\'][\''+key+'\'];'
|
||||
+'document.getElementById(\'screen\').innerHTML=renderScreen(\'staff_cat_confirm\')})();"'
|
||||
+' style="display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid rgba(0,0,0,.05);cursor:pointer">'
|
||||
+'<div style="width:20px;height:20px;border-radius:5px;border:1.5px solid '+(on?'var(--accent)':'rgba(0,0,0,.15)')+';background:'+(on?'var(--accent)':'transparent')+';display:flex;align-items:center;justify-content:center;flex-shrink:0">'
|
||||
+(on?'<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3"><polyline points="20 6 9 17 4 12"/></svg>':'')
|
||||
+'</div>'
|
||||
+'<span style="font-size:12px;color:'+(on?'var(--ink)':'var(--muted)')+';font-weight:'+(on?'600':'400')+'">'+label+'</span>'
|
||||
+'</div>';
|
||||
}
|
||||
|
||||
// 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 = '<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px">Назначить категорию</div>'
|
||||
+'<div style="padding:8px 10px;background:rgba(118,189,34,.08);border-radius:8px;font-size:12px;color:#4D7C0F;font-weight:500;margin-bottom:10px">'
|
||||
+'💡 Рекомендация системы: <strong>Кат.'+recommended+'</strong> на основе анкеты'
|
||||
+'</div>'
|
||||
+'<div style="display:flex;gap:8px;margin-bottom:12px">'
|
||||
+ catBtn2('A','Категория А','Премиальные объекты · Самостоятельная работа · Повышенная ставка','#4338CA')
|
||||
+ catBtn2('B','Категория Б','Стандартные объекты · Куратор при необходимости · Базовая ставка','#D97706')
|
||||
+'</div>'
|
||||
+(window._confirmCat===null ? '<div style="font-size:12px;color:var(--danger);text-align:center">Выберите категорию для продолжения</div>' : '')
|
||||
+'</div>';
|
||||
|
||||
var paramsSection = window._confirmCat===null ? '' : (
|
||||
'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:12px">Параметры</div>'
|
||||
+ counter('_confirmRate','Ставка за сборку, ₽',1000,5000)
|
||||
+ counter('_confirmSlots','Макс. заказов в день',1,6)
|
||||
+ counter('_confirmProb','Испытательный срок, нед.',1,12)
|
||||
+'</div>'
|
||||
+'<div class="card">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px">Допустимые типы мебели</div>'
|
||||
+'<div style="font-size:11px;color:var(--muted);margin-bottom:10px">'+(window._confirmCat==='A'?'Кат.А — полный доступ, снимите галку для запрета':'Кат.Б — ограниченный доступ, отметьте разрешённое')+'</div>'
|
||||
+ furnChk('corpus', 'Корпусная (шкафы, комоды, стеллажи)')
|
||||
+ furnChk('kitchen', 'Кухонные гарнитуры')
|
||||
+ furnChk('office', 'Офисная мебель')
|
||||
+ furnChk('upholstered','Мягкая мебель (диваны, кресла)')
|
||||
+ furnChk('premium', 'Премиальная / итальянская')
|
||||
+'</div>'
|
||||
+'<div class="card" style="background:rgba(0,0,0,.02)">'
|
||||
+'<div style="font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px">Примечание директора</div>'
|
||||
+'<textarea placeholder="Рекомендации, особые условия, ограничения..." style="width:100%;height:72px;padding:10px;border:1.5px solid rgba(0,0,0,.1);border-radius:10px;font-size:13px;font-family:inherit;resize:none;background:var(--bg);color:var(--ink);outline:none"></textarea>'
|
||||
+'</div>'
|
||||
+'<button onclick="navigate(\'staff_detail\')"'
|
||||
+' style="width:100%;padding:14px;background:var(--accent);color:#fff;border:none;border-radius:12px;font-size:15px;font-weight:700;cursor:pointer">'
|
||||
+'✓ Подтвердить категорию</button>'
|
||||
);
|
||||
|
||||
return '<div class="page">'
|
||||
+'<div class="page-header">'
|
||||
+'<button class="back-btn" onclick="navigate(\'staff_new\')">'
|
||||
+'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="15 18 9 12 15 6"/></svg>'
|
||||
+'</button>'
|
||||
+'<h2>Подтверждение категории</h2>'
|
||||
+'</div>'
|
||||
+'<div style="padding:16px">'
|
||||
+ catSection
|
||||
+ paramsSection
|
||||
+'</div>'
|
||||
+ navBar('staff')
|
||||
+'</div>';
|
||||
}
|
||||
|
||||
// ── SCREEN 4: STAFF BLOCK CONFIRM ─────────────────────────────
|
||||
function screenStaffBlockConfirm() {
|
||||
// Роль сотрудника — в реале берётся из профиля, здесь симулируем: 'asm'|'meas'|'both'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user