feat: workload analysis in days/weeks
Adds a "Нагрузка на сотрудника" block: days per cycle, weeks per cycle, total days/weeks per month at the current vacancy plan, and an overload/buffer card vs 21 working days a month. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f4ce3c97a2
commit
95fe078387
22
app.js
22
app.js
@ -2,6 +2,8 @@
|
||||
|
||||
const HOURS_MONTH = 168; // 21 рабочий день × 8 часов
|
||||
const MIN_DAY = 480; // 8 × 60
|
||||
const DAYS_WEEK = 5; // рабочая неделя
|
||||
const DAYS_MONTH = 21; // рабочих дней в месяце
|
||||
|
||||
const WORDS = {
|
||||
'один':1,'одна':1,'одной':1,'одного':1,
|
||||
@ -131,10 +133,18 @@ function metrics(items) {
|
||||
const bottleneck = total > 0 ? top3 / total * 100 : 0;
|
||||
const cost = state.salary > 0 ? state.salary * hours / HOURS_MONTH : null;
|
||||
|
||||
// Нагрузка в днях/неделях
|
||||
const daysPerCycle = total / MIN_DAY;
|
||||
const weeksPerCycle = daysPerCycle / DAYS_WEEK;
|
||||
const monthlyDays = state.vacancies * daysPerCycle;
|
||||
const monthlyWeeks = monthlyDays / DAYS_WEEK;
|
||||
const monthOverload = monthlyDays - DAYS_MONTH; // перегруз сверх месяца, дней
|
||||
|
||||
return {
|
||||
total, hours, count: items.length, avg: valid.length ? total / valid.length : 0,
|
||||
longest, top10, byGroup,
|
||||
fte, capacity, bottleneck, cost,
|
||||
daysPerCycle, weeksPerCycle, monthlyDays, monthlyWeeks, monthOverload,
|
||||
};
|
||||
}
|
||||
|
||||
@ -158,6 +168,18 @@ function render() {
|
||||
{ value: m.cost != null ? `${fmt(Math.round(m.cost))} ₸` : '—', label: 'Стоимость 1 цикла' },
|
||||
]);
|
||||
|
||||
renderCards('workload-kpi', [
|
||||
{ value: `${m.daysPerCycle.toFixed(1)} дн`, label: 'Нагрузка на 1 цикл', sub: '8-час. рабочий день' },
|
||||
{ value: `${m.weeksPerCycle.toFixed(2)} нед`, label: 'То же в неделях', sub: '5-дневка' },
|
||||
{ value: `${m.monthlyDays.toFixed(1)} дн`, label: `За месяц (${state.vacancies} вак.)`, sub: `план ${state.vacancies} × ${m.daysPerCycle.toFixed(1)} дн` },
|
||||
{ value: `${m.monthlyWeeks.toFixed(2)} нед`, label: 'То же в неделях', sub: `норма — ${(DAYS_MONTH/DAYS_WEEK).toFixed(1)} нед/мес` },
|
||||
{
|
||||
value: m.monthOverload >= 0 ? `+${m.monthOverload.toFixed(1)} дн` : `${m.monthOverload.toFixed(1)} дн`,
|
||||
label: m.monthOverload > 0 ? '⚠ Перегруз сверх месяца' : '✓ Запас в месяце',
|
||||
sub: m.monthOverload > 0 ? `нужно +${(m.monthOverload/DAYS_MONTH).toFixed(2)} FTE` : `свободно ${Math.abs(m.monthOverload).toFixed(1)} дн`,
|
||||
},
|
||||
]);
|
||||
|
||||
chartTop10(m.top10);
|
||||
chartGroups(m.byGroup);
|
||||
renderTable(items);
|
||||
|
||||
@ -39,6 +39,11 @@
|
||||
<div id="strategic-kpi" class="kpi-grid"></div>
|
||||
</section>
|
||||
|
||||
<section class="block">
|
||||
<h2>👤 Нагрузка на сотрудника (дни и недели)</h2>
|
||||
<div id="workload-kpi" class="kpi-grid"></div>
|
||||
</section>
|
||||
|
||||
<section class="charts-row">
|
||||
<div class="block">
|
||||
<h2>Топ-10 самых долгих функций</h2>
|
||||
@ -61,6 +66,6 @@
|
||||
|
||||
<p id="placeholder">Загрузка данных… Если дашборд не появился — нажмите «📁 Загрузить .xlsx».</p>
|
||||
|
||||
<script src="./app.js?v=3"></script>
|
||||
<script src="./app.js?v=4"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user