262 lines
10 KiB
HTML
262 lines
10 KiB
HTML
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>HR Onboarding — приём сотрудников</title>
|
||
<style>
|
||
* { margin: 0; box-sizing: border-box; }
|
||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f5f7fa; color: #1a1a1a; padding: 24px; }
|
||
.container { max-width: 1200px; margin: 0 auto; }
|
||
h1 { font-size: 28px; margin-bottom: 8px; color: #0f141f; }
|
||
.subtitle { color: #6b7280; margin-bottom: 32px; }
|
||
|
||
.layout { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; }
|
||
@media (max-width: 900px) { .layout { grid-template-columns: 1fr; } }
|
||
|
||
.card { background: white; border-radius: 12px; padding: 24px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
||
.card h2 { font-size: 20px; margin-bottom: 20px; color: #0f141f; display: flex; align-items: center; gap: 8px; }
|
||
|
||
.form-group { margin-bottom: 16px; }
|
||
.form-group label { display: block; font-size: 14px; font-weight: 500; margin-bottom: 6px; color: #374151; }
|
||
.form-group input, .form-group select { width: 100%; padding: 10px 12px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; transition: border-color 0.2s; }
|
||
.form-group input:focus, .form-group select:focus { outline: none; border-color: #3b82f6; }
|
||
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||
|
||
.btn { background: #3b82f6; color: white; border: none; padding: 12px 24px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; width: 100%; transition: background 0.2s; }
|
||
.btn:hover { background: #2563eb; }
|
||
.btn:disabled { background: #9ca3af; cursor: not-allowed; }
|
||
|
||
.status { margin-top: 16px; padding: 12px; border-radius: 8px; font-size: 14px; display: none; }
|
||
.status.success { background: #dcfce7; color: #166534; border: 1px solid #86efac; display: block; }
|
||
.status.error { background: #fee2e2; color: #991b1b; border: 1px solid #fca5a5; display: block; }
|
||
.status.loading { background: #dbeafe; color: #1e40af; border: 1px solid #93c5fd; display: block; }
|
||
|
||
.search-box { margin-bottom: 16px; }
|
||
.search-box input { width: 100%; padding: 10px 12px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; }
|
||
|
||
table { width: 100%; border-collapse: collapse; }
|
||
th, td { padding: 12px; text-align: left; border-bottom: 1px solid #e5e7eb; font-size: 14px; }
|
||
th { font-weight: 600; color: #6b7280; background: #f9fafb; }
|
||
tr:hover { background: #f9fafb; }
|
||
.empty { text-align: center; color: #9ca3af; padding: 40px; }
|
||
|
||
.badge { display: inline-block; padding: 4px 10px; border-radius: 999px; font-size: 12px; font-weight: 500; }
|
||
.badge-new { background: #dbeafe; color: #1e40af; }
|
||
.badge-sap { background: #dcfce7; color: #166534; }
|
||
|
||
.emp-number { font-family: monospace; font-size: 15px; font-weight: 600; color: #059669; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>HR Onboarding</h1>
|
||
<p class="subtitle">Приём новых сотрудников в систему</p>
|
||
|
||
<div class="layout">
|
||
<div class="card">
|
||
<h2>📝 Новый сотрудник</h2>
|
||
<form id="employeeForm">
|
||
<div class="form-group">
|
||
<label>ФИО полностью</label>
|
||
<input type="text" name="fullName" placeholder="Иванов Иван Иванович" required>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>Дата рождения</label>
|
||
<input type="date" name="birthDate" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>ИНН</label>
|
||
<input type="text" name="inn" placeholder="123456789012" pattern="\d{12}" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Подразделение</label>
|
||
<select name="department" required>
|
||
<option value="">Выберите подразделение</option>
|
||
<option value="IT">IT-департамент</option>
|
||
<option value="HR">HR-отдел</option>
|
||
<option value="Finance">Финансовый отдел</option>
|
||
<option value="Sales">Отдел продаж</option>
|
||
<option value="Marketing">Маркетинг</option>
|
||
<option value="Operations">Операционный отдел</option>
|
||
<option value="Legal">Юридический отдел</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Должность</label>
|
||
<input type="text" name="position" placeholder="Менеджер по продажам" required>
|
||
</div>
|
||
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>Дата приёма</label>
|
||
<input type="date" name="hireDate" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Тип договора</label>
|
||
<select name="contractType" required>
|
||
<option value="permanent">Бессрочный</option>
|
||
<option value="fixed">Срочный</option>
|
||
<option value="parttime">Частичная занятость</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn" id="submitBtn">Отправить в SAP</button>
|
||
|
||
<div id="status" class="status"></div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>📋 Сотрудники</h2>
|
||
<div class="search-box">
|
||
<input type="text" id="search" placeholder="Поиск по ФИО, должности, подразделению...">
|
||
</div>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Табельный</th>
|
||
<th>ФИО</th>
|
||
<th>Должность</th>
|
||
<th>Подразделение</th>
|
||
<th>Статус</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="employeesTable">
|
||
<tr class="empty"><td colspan="5">Сотрудников пока нет</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Мок-данные — имитация базы сотрудников
|
||
let employees = [];
|
||
let nextId = 1001;
|
||
|
||
// Имитация отправки в SAP
|
||
async function sendToSap(employeeData) {
|
||
// Имитация задержки сети
|
||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||
|
||
// Генерация табельного номера (как в SAP)
|
||
const tabNumber = String(nextId++).padStart(8, '0');
|
||
|
||
return {
|
||
success: true,
|
||
tabNumber: tabNumber,
|
||
sapId: 'SAP-' + Math.random().toString(36).slice(2, 10).toUpperCase()
|
||
};
|
||
}
|
||
|
||
// Отрисовка таблицы
|
||
function renderTable(data = employees) {
|
||
const tbody = document.getElementById('employeesTable');
|
||
|
||
if (data.length === 0) {
|
||
tbody.innerHTML = '<tr class="empty"><td colspan="5">Сотрудников не найдено</td></tr>';
|
||
return;
|
||
}
|
||
|
||
tbody.innerHTML = data.map(emp => `
|
||
<tr>
|
||
<td><span class="emp-number">${emp.tabNumber}</span></td>
|
||
<td>${emp.fullName}</td>
|
||
<td>${emp.position}</td>
|
||
<td>${emp.department}</td>
|
||
<td><span class="badge badge-sap">✓ В SAP</span></td>
|
||
</tr>
|
||
`).join('');
|
||
}
|
||
|
||
// Поиск
|
||
function search(query) {
|
||
const q = query.toLowerCase();
|
||
const filtered = employees.filter(emp =>
|
||
emp.fullName.toLowerCase().includes(q) ||
|
||
emp.position.toLowerCase().includes(q) ||
|
||
emp.department.toLowerCase().includes(q)
|
||
);
|
||
renderTable(filtered);
|
||
}
|
||
|
||
// Обработка формы
|
||
document.getElementById('employeeForm').addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
|
||
const form = e.target;
|
||
const btn = document.getElementById('submitBtn');
|
||
const status = document.getElementById('status');
|
||
|
||
// Сбор данных
|
||
const employeeData = {
|
||
fullName: form.fullName.value,
|
||
birthDate: form.birthDate.value,
|
||
inn: form.inn.value,
|
||
department: form.department.value,
|
||
position: form.position.value,
|
||
hireDate: form.hireDate.value,
|
||
contractType: form.contractType.value
|
||
};
|
||
|
||
// UI: загрузка
|
||
btn.disabled = true;
|
||
btn.textContent = 'Отправка в SAP...';
|
||
status.className = 'status loading';
|
||
status.textContent = '⏳ Подключение к SAP...';
|
||
|
||
try {
|
||
// Отправка в SAP (мок)
|
||
const result = await sendToSap(employeeData);
|
||
|
||
// Добавление в базу
|
||
const newEmployee = {
|
||
...employeeData,
|
||
tabNumber: result.tabNumber,
|
||
sapId: result.sapId,
|
||
createdAt: new Date().toISOString()
|
||
};
|
||
employees.unshift(newEmployee);
|
||
|
||
// UI: успех
|
||
status.className = 'status success';
|
||
status.innerHTML = `✅ Сотрудник успешно добавлен! <strong>Табельный номер: ${result.tabNumber}</strong>`;
|
||
|
||
// Сброс формы
|
||
form.reset();
|
||
renderTable();
|
||
|
||
} catch (error) {
|
||
// UI: ошибка
|
||
status.className = 'status error';
|
||
status.textContent = '❌ Ошибка подключения к SAP. Попробуйте позже.';
|
||
|
||
} finally {
|
||
btn.disabled = false;
|
||
btn.textContent = 'Отправить в SAP';
|
||
|
||
// Скрыть статус через 5 сек
|
||
setTimeout(() => {
|
||
status.className = 'status';
|
||
}, 5000);
|
||
}
|
||
});
|
||
|
||
// Поиск
|
||
document.getElementById('search').addEventListener('input', (e) => {
|
||
search(e.target.value);
|
||
});
|
||
|
||
// Установка сегодняшней даты по умолчанию
|
||
document.querySelector('[name="hireDate"]').valueAsDate = new Date();
|
||
</script>
|
||
</body>
|
||
</html>
|