Калькулятор стоимости подбора персонала
Калькулятор услуг кадрового агентства: считает стоимость подбора от оклада кандидата и уровня позиции, показывает цену за одну позицию, срок до выхода и расшифровку наценок.
<section class="vbksp">
<div class="vbksp-wrap">
<div class="vbksp-head">
<h2 class="vbksp-h2">Во сколько обойдётся закрытие вакансии</h2>
<p class="vbksp-lead">Укажите уровень позиции, оклад кандидата и число мест. Калькулятор покажет стоимость работы, цену за одну позицию и срок до выхода человека.</p>
</div>
<div class="vbksp-grid">
<div class="vbksp-form">
<div class="vbksp-field">
<label class="vbksp-lbl" for="vbksp-level">Уровень позиции</label>
<select id="vbksp-level" class="vbksp-sel"></select>
</div>
<div class="vbksp-field">
<div class="vbksp-lbl vbksp-lbl--row"><span>Оклад кандидата в месяц</span><b id="vbksp-payv">80 000 ₽</b></div>
<input type="range" id="vbksp-pay" min="40" max="500" step="10" value="80" aria-label="Оклад кандидата в тысячах рублей">
<div class="vbksp-ticks"><i>40 тыс.</i><i>270 тыс.</i><i>500 тыс.</i></div>
</div>
<div class="vbksp-field">
<div class="vbksp-lbl vbksp-lbl--row"><span>Сколько позиций закрываем</span><b id="vbksp-cntv">1</b></div>
<input type="range" id="vbksp-cnt" min="1" max="20" step="1" value="1" aria-label="Число позиций">
<div class="vbksp-ticks"><i>1</i><i>10</i><i>20</i></div>
</div>
<div class="vbksp-field">
<span class="vbksp-lbl">Срочность</span>
<div class="vbksp-seg" id="vbksp-urg"></div>
</div>
<div class="vbksp-field">
<span class="vbksp-lbl">Гарантия замены</span>
<div class="vbksp-seg" id="vbksp-war"></div>
</div>
</div>
<div class="vbksp-out">
<div class="vbksp-sum">
<span>Стоимость подбора</span>
<b id="vbksp-total">0 ₽</b>
</div>
<div class="vbksp-pair">
<div><span>За одну позицию</span><b id="vbksp-one">0 ₽</b></div>
<div><span>Срок до выхода</span><b id="vbksp-days">0</b></div>
</div>
<ul class="vbksp-rows" id="vbksp-rows"></ul>
<a class="vbksp-cta" href="#zayavka">Обсудить вакансию</a>
<p class="vbksp-note">Расчёт ориентировочный. Итог фиксируем в договоре после снятия профиля должности, счёт выставляем в день выхода кандидата на работу.</p>
</div>
</div>
</div>
</section>
<style>
.vbksp, .vbksp *, .vbksp *::before, .vbksp *::after { box-sizing: border-box; }
.vbksp {
--acc: #d9822b; --ink: #221c14; --muted: #6c6157; --line: #e6e0d6; --bg: #faf7f2; --panel: #fff;
--f: var(--t-text-font, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif);
--fh: var(--t-headline-font, var(--f));
background: var(--bg); color: var(--ink); font-family: var(--f); padding: clamp(36px, 5vw, 80px) 20px;
}
.vbksp-wrap { max-width: 1120px; margin: 0 auto; padding: 0 clamp(0px, 2vw, 40px); }
.vbksp-head { max-width: 44em; margin-bottom: clamp(22px, 3vw, 36px); }
.vbksp-h2 { font-family: var(--fh); font-size: clamp(26px, 3.4vw, 40px); line-height: 1.1; font-weight: 700; letter-spacing: -.02em; margin: 0 0 12px; }
.vbksp-lead { font-size: 16px; line-height: 1.6; color: var(--muted); margin: 0; }
.vbksp-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr); gap: 16px; align-items: start; }
.vbksp-form { background: var(--panel); border: 1px solid var(--line); border-radius: 22px; padding: clamp(20px, 2.4vw, 30px); display: grid; gap: 22px; }
.vbksp-lbl { display: block; font-size: 14px; color: var(--muted); margin-bottom: 10px; }
.vbksp-lbl--row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.vbksp-lbl--row b { font-family: var(--fh); font-size: 19px; color: var(--ink); white-space: nowrap; }
.vbksp-sel { width: 100%; height: 52px; padding: 0 38px 0 15px; font: inherit; font-size: 16px; -webkit-appearance: none; appearance: none;
border: 1.5px solid var(--line); border-radius: 12px; background: var(--panel); color: var(--ink);
background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
background-position: calc(100% - 19px) 23px, calc(100% - 13px) 23px; background-size: 6px 6px, 6px 6px; background-repeat: no-repeat; }
.vbksp-sel:focus { outline: 2px solid var(--acc); outline-offset: -2px; }
.vbksp input[type=range] { -webkit-appearance: none; appearance: none; width: 100%; height: 4px; border-radius: 4px; background: #e3dcd1; outline: none; }
.vbksp input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 24px; height: 24px; border-radius: 50%;
background: var(--acc); border: 4px solid var(--panel); box-shadow: 0 1px 6px rgba(0,0,0,.2); cursor: pointer; }
.vbksp input[type=range]::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: var(--acc); border: 3px solid var(--panel); cursor: pointer; }
.vbksp-ticks { display: flex; justify-content: space-between; margin-top: 7px; font-size: 11px; color: #a2988b; }
.vbksp-ticks i { font-style: normal; }
.vbksp-seg { display: grid; grid-template-columns: repeat(auto-fit, minmax(94px, 1fr)); gap: 7px; }
.vbksp-opt { border: 1.5px solid var(--line); margin: 0; padding: 12px 8px; -webkit-appearance: none; appearance: none; font: inherit; font-size: 13.5px;
cursor: pointer; border-radius: 12px; background: var(--panel) !important; color: var(--muted) !important; transition: .18s ease; }
.vbksp-opt:hover { border-color: var(--acc); }
.vbksp-opt[aria-pressed="true"] { background: var(--acc) !important; color: #fff !important; border-color: var(--acc); }
.vbksp-out { background: #221c14; color: #f4efe7; border-radius: 22px; padding: clamp(22px, 2.6vw, 30px); }
.vbksp-sum span { display: block; font-size: 13px; color: #b3a696; margin-bottom: 6px; }
.vbksp-sum b { font-family: var(--fh); font-size: clamp(32px, 4.4vw, 46px); line-height: 1.05; font-weight: 700; letter-spacing: -.025em; color: var(--acc); }
.vbksp-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin: 22px 0; }
.vbksp-pair div { background: rgba(255,255,255,.06); border-radius: 14px; padding: 14px 16px; }
.vbksp-pair span { display: block; font-size: 12.5px; color: #b3a696; margin-bottom: 4px; }
.vbksp-pair b { font-family: var(--fh); font-size: 20px; font-weight: 700; }
.vbksp-rows { list-style: none; margin: 0 0 22px; padding: 0; display: grid; gap: 10px; }
.vbksp-rows li { display: flex; justify-content: space-between; gap: 14px; font-size: 13.5px; border-top: 1px solid rgba(255,255,255,.1); padding-top: 10px; }
.vbksp-rows li span { color: #b3a696; }
.vbksp-rows li b { font-weight: 600; text-align: right; white-space: nowrap; }
.vbksp-cta, .vbksp-cta:link, .vbksp-cta:visited, .vbksp-cta:active, .vbksp-cta:focus { display: flex; align-items: center; justify-content: center;
min-height: 56px; padding: 0 24px; border-radius: 12px; font-size: 16px; font-weight: 600;
background: var(--acc); color: #fff !important; text-decoration: none !important; transition: filter .2s ease; }
.vbksp-cta:hover { filter: brightness(1.08); color: #fff !important; }
.vbksp-note { margin: 16px 0 0; font-size: 12px; line-height: 1.55; color: #9c9184; }
@media (max-width: 860px) { .vbksp-grid { grid-template-columns: minmax(0, 1fr); } }
@media (prefers-reduced-motion: reduce) { .vbksp * { transition: none !important; } }
</style>
<script>
(function () {
/* ── КОЭФФИЦИЕНТЫ ПОДБОРА ──
fee, доля месячного оклада за одну закрытую позицию;
days, базовый срок до выхода; min, нижняя граница чека */
var LEVELS = [
{ n: 'Линейный персонал', fee: 0.55, days: 9, min: 18000 },
{ n: 'Специалист', fee: 1.00, days: 16, min: 35000 },
{ n: 'Руководитель отдела', fee: 1.60, days: 28, min: 90000 },
{ n: 'Директор направления', fee: 2.20, days: 45, min: 180000 }
];
var URGENCY = [
{ n: 'Плановая', k: 1, d: 1 },
{ n: 'Ускоренная', k: 1.2, d: .75 },
{ n: 'Срочная', k: 1.45, d: .55 }
];
var WARRANTY = [
{ n: '30 дней', k: 1 },
{ n: '90 дней', k: 1.1 },
{ n: '180 дней', k: 1.22 }
];
/* скидка за объём: от скольких позиций и множитель */
var VOLUME = [ { from: 11, k: .8 }, { from: 6, k: .87 }, { from: 3, k: .93 }, { from: 1, k: 1 } ];
var roots = document.querySelectorAll('.vbksp');
for (var i = 0; i < roots.length; i++) init(roots[i]);
function init(root) {
if (root.__vb) return; root.__vb = 1;
var $ = function (s) { return root.querySelector(s); };
var st = { lv: 1, pay: 80, cnt: 1, urg: 0, war: 1 };
function fmt(n) { return String(Math.round(n / 100) * 100).replace(/\B(?=(\d{3})+(?!\d))/g, ' '); }
function plural(n, a) { var m = n % 100; if (m > 4 && m < 21) return a[2]; m = n % 10; return m === 1 ? a[0] : (m > 1 && m < 5 ? a[1] : a[2]); }
$('#vbksp-level').innerHTML = LEVELS.map(function (l, i) {
return '<option value="' + i + '"' + (i === st.lv ? ' selected' : '') + '>' + l.n + '<\/option>';
}).join('');
function seg(box, list, key) {
box.innerHTML = list.map(function (o, i) {
return '<button type="button" class="vbksp-opt" data-i="' + i + '" aria-pressed="' + (i === st[key]) + '">' + o.n + '<\/button>';
}).join('');
box.addEventListener('click', function (e) {
var b = e.target.closest ? e.target.closest('.vbksp-opt') : null;
if (!b) return;
st[key] = +b.getAttribute('data-i');
var bs = box.querySelectorAll('.vbksp-opt');
for (var i = 0; i < bs.length; i++) bs[i].setAttribute('aria-pressed', i === st[key] ? 'true' : 'false');
render();
});
}
seg($('#vbksp-urg'), URGENCY, 'urg');
seg($('#vbksp-war'), WARRANTY, 'war');
$('#vbksp-level').addEventListener('change', function () { st.lv = +this.value; render(); });
$('#vbksp-pay').addEventListener('input', function () { st.pay = +this.value; render(); });
$('#vbksp-cnt').addEventListener('input', function () { st.cnt = +this.value; render(); });
function render() {
var lv = LEVELS[st.lv], ur = URGENCY[st.urg], wr = WARRANTY[st.war];
var vol = VOLUME[0];
for (var i = 0; i < VOLUME.length; i++) if (st.cnt >= VOLUME[i].from) { vol = VOLUME[i]; break; }
var base = st.pay * 1000 * lv.fee;
if (base < lv.min) base = lv.min;
var one = base * ur.k * wr.k * vol.k;
var total = one * st.cnt;
var days = Math.round(lv.days * ur.d + Math.ceil((st.cnt - 1) / 3) * 2);
$('#vbksp-payv').textContent = fmt(st.pay * 1000) + ' ₽';
$('#vbksp-cntv').textContent = st.cnt + ' ' + plural(st.cnt, ['позиция', 'позиции', 'позиций']);
$('#vbksp-total').textContent = fmt(total) + ' ₽';
$('#vbksp-one').textContent = fmt(one) + ' ₽';
$('#vbksp-days').textContent = days + ' ' + plural(days, ['день', 'дня', 'дней']);
var rows = [
['Ставка за позицию', Math.round(lv.fee * 100) + '% оклада'],
['Срочность', ur.n + (ur.k > 1 ? ', плюс ' + Math.round((ur.k - 1) * 100) + '%' : ', без наценки')],
['Гарантия замены', wr.n + (wr.k > 1 ? ', плюс ' + Math.round((wr.k - 1) * 100) + '%' : ', входит в цену')],
['Скидка за объём', vol.k < 1 ? Math.round((1 - vol.k) * 100) + '%' : 'от 3 позиций']
];
$('#vbksp-rows').innerHTML = rows.map(function (r) {
return '<li><span>' + r[0] + '<\/span><b>' + r[1] + '<\/b><\/li>';
}).join('');
}
render();
}
})();
</script> Вставляется целиком в блок T123 «HTML-код». Внутри уже есть стили и скрипт, подключать ничего не нужно.
Как вставить блок в Tilda
- Скопируйте кодКнопка «Скопировать код» выше кладёт всё содержимое в буфер обмена.
- Добавьте блок T123В редакторе страницы: «Библиотека блоков» → «Другое» → T123 «HTML-код».
- Вставьте и сохранитеНажмите «Контент», вставьте код в поле, сохраните и обновите страницу.
- ОпубликуйтеВ превью скрипты Tilda работают не всегда — проверяйте на опубликованной странице.
Подробная инструкция с граблями — как вставить вайб-блок в Tilda.
Что менять под себя
| Где в коде | За что отвечает |
|---|---|
LEVELS в начале скрипта | уровни позиций, доля оклада, базовый срок и минимальный чек |
URGENCY и WARRANTY | наценки за срочность и за длинный гарантийный период |
VOLUME в начале скрипта | пороги и размер скидки при подборе группы позиций |
href у кнопки в правой карточке | адрес блока с заявкой или страницы контактов |
Калькулятор стоимости подбора: зачем он нужен
Стоимость подбора обычно считают в окладах кандидата, и работодателю трудно перевести это в деньги без менеджера. Калькулятор делает перевод сам: посетитель выбирает уровень позиции, двигает ползунок оклада и число мест, отмечает срочность и гарантийный период. В ответ выходят три числа: общая сумма, цена за одну позицию и срок до выхода человека. Под ними лежит расшифровка из четырёх строк, где видно ставку, наценку за срочность, наценку за гарантию и скидку за объём.
Все коэффициенты собраны в четыре объекта в начале скрипта. LEVELS задаёт долю оклада, базовый срок и нижнюю границу чека для каждого уровня, URGENCY меняет цену и срок, WARRANTY добавляет процент за длинную гарантию, VOLUME даёт скидку от трёх, шести и одиннадцати позиций. Ставку легко переписать под свой прайс, не трогая разметку и стили. Итог округляется до сотен рублей, а под кнопкой стоит оговорка, что цена фиксируется в договоре после снятия профиля должности.
Вопросы по этому блоку
-
Замените значения fee и min в массиве LEVELS: fee считается долей месячного оклада за одну позицию, min задаёт нижнюю границу чека. Остальная арифметика подстроится без правок.
-
Оставьте в массиве WARRANTY один объект с коэффициентом единица, тогда переключатель покажет одну кнопку. Проще удалить и сам блок поля из разметки вместе с вызовом seg для этого переключателя.
-
Базовый срок лежит в поле days каждого уровня, он умножается на коэффициент срочности и растёт на два дня за каждые три дополнительные позиции. Значения меняются в тех же объектах.
-
Да. Код на этой странице копируется целиком, без регистрации и подписки. Указывать авторство не нужно, использовать можно в коммерческих проектах.
-
Нет. Все классы внутри имеют собственный префикс vbksp, поэтому не пересекаются ни со стилями Tilda, ни с другими блоками. Скрипт привязан к своему элементу и запускается один раз, даже если блок вставлен дважды.
-
Раскладка перестраивается под узкие экраны, размеры заданы через clamp, поля ввода имеют шрифт 16 пикселей — iOS не будет зумить страницу при фокусе. Отдельной мобильной версии подключать не нужно.
Другие калькуляторы
Ещё блоки для подбора персонала
Собрать сайт целиком, а не по блокам
Дровосеки делают сайты на Tilda под ключ: структура, тексты, дизайн, вёрстка и вайб-блоки под задачи бизнеса.