zov-survey/survey_webapp.html

259 lines
11 KiB
HTML
Raw Permalink 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.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Анкета сборщика · ЗОВ</title>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<style>
:root {
--bg: var(--tg-theme-bg-color, #ffffff);
--txt: var(--tg-theme-text-color, #1e293b);
--hint:var(--tg-theme-hint-color, #64748b);
--sec: var(--tg-theme-secondary-bg-color, #f1f5f9);
--btn: var(--tg-theme-button-color, #4f46e5);
--btx: var(--tg-theme-button-text-color, #ffffff);
--sep: rgba(0,0,0,.07);
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:-apple-system,'Segoe UI',system-ui,sans-serif;
background:var(--bg);color:var(--txt);
padding:16px;padding-bottom:90px;font-size:15px}
.sec-title{font-size:11px;font-weight:700;text-transform:uppercase;
letter-spacing:.6px;color:var(--hint);margin:20px 0 8px}
/* Поля */
.fgroup{background:var(--sec);border-radius:12px;overflow:hidden}
.frow{display:flex;flex-direction:column;padding:11px 14px;
border-bottom:1px solid var(--sep)}
.frow:last-child{border-bottom:none}
.flabel{font-size:11px;color:var(--hint);margin-bottom:3px;font-weight:600}
.finput{background:transparent;border:none;outline:none;
font-size:15px;color:var(--txt);width:100%;padding:0}
.finput::placeholder{color:var(--hint)}
/* Инструмент */
.tlist{background:var(--sec);border-radius:12px;overflow:hidden}
.titem{display:flex;align-items:center;gap:12px;
padding:13px 14px;border-bottom:1px solid var(--sep);
cursor:pointer;-webkit-tap-highlight-color:transparent;
transition:background .1s}
.titem:last-child{border-bottom:none}
.titem:active{background:rgba(0,0,0,.04)}
.tcheck{width:22px;height:22px;border-radius:50%;border:2px solid #cbd5e1;
flex-shrink:0;display:flex;align-items:center;justify-content:center;
transition:all .15s}
.titem.on .tcheck{background:var(--btn);border-color:var(--btn)}
.tcheck svg{display:none}
.titem.on .tcheck svg{display:block}
.tico{font-size:20px;flex-shrink:0;width:26px;text-align:center}
.tname{flex:1;font-size:14px;line-height:1.35}
.tpts{font-size:11px;color:var(--hint);background:rgba(0,0,0,.06);
padding:2px 7px;border-radius:10px;font-weight:700;white-space:nowrap}
.tpts.pro{background:#ede9fe;color:#6d28d9}
/* Результат */
.scard{background:var(--sec);border-radius:12px;padding:16px;
display:flex;align-items:center;gap:14px}
.scirc{width:64px;height:64px;border-radius:50%;border:3px solid #e2e8f0;
display:flex;flex-direction:column;align-items:center;
justify-content:center;flex-shrink:0;transition:border-color .3s}
.snum{font-size:18px;font-weight:800;line-height:1;transition:color .3s}
.smax{font-size:10px;color:var(--hint)}
.sinfo{flex:1}
.scat{font-size:16px;font-weight:700;margin-bottom:5px}
.sbar-wrap{height:6px;background:#e2e8f0;border-radius:3px;overflow:hidden}
.sbar{height:100%;border-radius:3px;transition:width .3s,background .3s;width:0%}
.spct{font-size:11px;color:var(--hint);margin-top:4px}
/* Ошибка */
.err{display:none;color:#dc2626;font-size:12px;padding:8px 14px;
background:#fef2f2;border-radius:8px;margin-top:8px}
.err.show{display:block}
/* Success overlay */
.success{display:none;position:fixed;inset:0;background:var(--bg);
flex-direction:column;align-items:center;justify-content:center;
gap:12px;text-align:center;padding:32px;z-index:100}
.success.show{display:flex}
.success-icon{font-size:64px}
.success-title{font-size:20px;font-weight:700}
.success-sub{font-size:14px;color:var(--hint);max-width:260px}
/* Кнопка */
.bar{position:fixed;bottom:0;left:0;right:0;padding:12px 16px;
background:var(--bg);border-top:1px solid var(--sep)}
.sbtn{width:100%;padding:14px;background:var(--btn);color:var(--btx);
border:none;border-radius:12px;font-size:15px;font-weight:600;
cursor:pointer;transition:opacity .15s}
.sbtn:active{opacity:.8}
.sbtn:disabled{opacity:.45;cursor:not-allowed}
</style>
</head>
<body>
<div class="sec-title">Личные данные</div>
<div class="fgroup">
<div class="frow">
<div class="flabel">ФИО</div>
<input class="finput" id="fio" type="text" placeholder="Иванов Иван Иванович"
autocomplete="name" autocorrect="off" spellcheck="false">
</div>
<div class="frow">
<div class="flabel">Дата рождения</div>
<input class="finput" id="dob" type="text" placeholder="15.03.1990"
inputmode="numeric" maxlength="10">
</div>
</div>
<div class="err" id="err">Заполните ФИО и дату рождения</div>
<div class="sec-title">Инструмент</div>
<div class="tlist" id="tlist"></div>
<div class="sec-title">Результат</div>
<div class="scard">
<div class="scirc" id="scirc">
<span class="snum" id="snum">0</span>
<span class="smax" id="smax">/ 17</span>
</div>
<div class="sinfo">
<div class="scat" id="scat">🥉 Базовый</div>
<div class="sbar-wrap"><div class="sbar" id="sbar"></div></div>
<div class="spct" id="spct">0% — отметьте инструмент</div>
</div>
</div>
<!-- Экран успеха -->
<div class="success" id="success">
<div class="success-icon"></div>
<div class="success-title">Анкета отправлена!</div>
<div class="success-sub">Ожидайте подтверждения категории от руководства</div>
</div>
<div class="bar">
<button class="sbtn" id="sbtn" onclick="doSubmit()">Отправить анкету</button>
</div>
<script>
const tg = window.Telegram.WebApp;
tg.ready();
tg.expand();
const TOOLS = [
{key:"drill", ico:"🔩", name:"Шуруповёрт / дрель", pts:1},
{key:"perforator", ico:"⚒️", name:"Перфоратор", pts:1},
{key:"perf_dust", ico:"💨", name:"Насадка пылеотсоса для перфоратора", pts:1},
{key:"jigsaw", ico:"🪚", name:"Электролобзик", pts:1},
{key:"plunge_saw", ico:"🔪", name:"Погружная (дисковая) пила", pts:2},
{key:"guide_rail", ico:"📏", name:"Шина направляющая", pts:1},
{key:"grinder", ico:"⚙️", name:"Угловая шлифмашина (болгарка)", pts:1},
{key:"router", ico:"🔧", name:"Фрезер", pts:1},
{key:"laser", ico:"📐", name:"Лазерный уровень", pts:1},
{key:"vacuum", ico:"🧹", name:"Строительный пылесос", pts:1},
{key:"clamps", ico:"🗜️", name:"Струбцины / зажимы (набор ≥4 шт.)", pts:1},
{key:"templates", ico:"📋", name:"Мебельные шаблоны / кондукторы", pts:1},
{key:"stepladder", ico:"🪜", name:"Стремянка", pts:1},
{key:"hand_tools", ico:"🔨", name:"Ручной инструмент (молоток, стамески, ключи)", pts:1},
{key:"car", ico:"🚗", name:"Личный автомобиль", pts:2},
];
const MAX = TOOLS.reduce((s,t) => s+t.pts, 0); // 17
document.getElementById('smax').textContent = '/ ' + MAX;
const state = {};
TOOLS.forEach(t => state[t.key] = false);
// Рендер списка
const tlist = document.getElementById('tlist');
TOOLS.forEach(t => {
const el = document.createElement('div');
el.className = 'titem';
el.id = 'ti_' + t.key;
const ptsCls = t.pts === 2 ? 'tpts pro' : 'tpts';
const ptsLbl = t.pts === 2 ? '+2 б' : '+1 б';
el.innerHTML = `
<div class="tcheck">
<svg width="12" height="10" viewBox="0 0 12 10">
<path d="M1 5L4.5 8.5L11 1" stroke="white" stroke-width="2.2"
stroke-linecap="round" stroke-linejoin="round" fill="none"/>
</svg>
</div>
<span class="tico">${t.ico}</span>
<span class="tname">${t.name}</span>
<span class="${ptsCls}">${ptsLbl}</span>`;
el.addEventListener('click', () => {
state[t.key] = !state[t.key];
el.classList.toggle('on', state[t.key]);
updateScore();
});
tlist.appendChild(el);
});
function updateScore() {
const score = TOOLS.reduce((s,t) => s + (state[t.key] ? t.pts : 0), 0);
const pct = Math.round(score / MAX * 100);
document.getElementById('snum').textContent = score;
let cat, color;
if (pct >= 80) { cat = '🥇 Мастер'; color = '#16a34a'; }
else if (pct >= 50) { cat = '🥈 Специалист'; color = '#d97706'; }
else { cat = '🥉 Базовый'; color = '#64748b'; }
document.getElementById('scat').textContent = cat;
document.getElementById('sbar').style.cssText = `width:${pct}%;background:${color}`;
document.getElementById('spct').textContent = pct + '%';
document.getElementById('scirc').style.borderColor = color;
document.getElementById('snum').style.color = color;
}
// Автоформат ДР: 15.03.1990
document.getElementById('dob').addEventListener('input', function(e) {
let v = e.target.value.replace(/\D/g,'');
if (v.length > 2) v = v.slice(0,2) + '.' + v.slice(2);
if (v.length > 5) v = v.slice(0,5) + '.' + v.slice(5);
e.target.value = v.slice(0,10);
});
function doSubmit() {
const fio = document.getElementById('fio').value.trim();
const dob = document.getElementById('dob').value.trim();
const err = document.getElementById('err');
if (!fio || !dob) {
err.className = 'err show';
err.textContent = !fio ? 'Введите ФИО' : 'Введите дату рождения (например: 15.03.1990)';
document.getElementById(fio ? 'dob' : 'fio').focus();
return;
}
err.className = 'err';
const score = TOOLS.reduce((s,t) => s + (state[t.key] ? t.pts : 0), 0);
const pct = Math.round(score / MAX * 100);
let category;
if (pct >= 80) category = '🥇 Мастер';
else if (pct >= 50) category = '🥈 Специалист';
else category = '🥉 Базовый';
const payload = JSON.stringify({fio, dob, tools: state, score, max_score: MAX, pct, category});
// Показываем success-экран сразу (до отправки — UX)
document.getElementById('success').className = 'success show';
document.getElementById('sbtn').disabled = true;
// Отправляем данные в бот и закрываем
try {
tg.sendData(payload);
} catch(e) {
console.error('sendData error:', e);
}
// Fallback: если Telegram не закрыл сам — закрыть через 1.5 сек
setTimeout(() => {
try { tg.close(); } catch(e) {}
}, 1500);
}
updateScore();
</script>
</body>
</html>