shtat-sok-employees/index.html

653 lines
24 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.0">
<title>Карточки сотрудников СОК-1 СД</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
min-height: 100vh;
color: #eee;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
header {
text-align: center;
padding: 30px 0;
border-bottom: 2px solid #e94560;
margin-bottom: 30px;
}
header h1 {
color: #e94560;
font-size: 2.5rem;
margin-bottom: 10px;
}
header p {
color: #aaa;
font-size: 1.1rem;
}
.filters {
background: rgba(255, 255, 255, 0.05);
padding: 20px;
border-radius: 10px;
margin-bottom: 30px;
display: flex;
flex-wrap: wrap;
gap: 15px;
align-items: center;
}
.filter-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.filter-group label {
font-size: 0.85rem;
color: #aaa;
}
.filter-group input,
.filter-group select {
padding: 10px 15px;
border: 1px solid #444;
border-radius: 5px;
background: #1a1a2e;
color: #eee;
font-size: 1rem;
}
.filter-group input:focus,
.filter-group select:focus {
outline: none;
border-color: #e94560;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.stat-card {
background: linear-gradient(135deg, #e94560 0%, #c23a51 100%);
padding: 20px;
border-radius: 10px;
text-align: center;
}
.stat-card h3 {
font-size: 2rem;
margin-bottom: 5px;
}
.stat-card p {
font-size: 0.9rem;
opacity: 0.9;
}
.employees-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(450px, 1fr));
gap: 25px;
}
.employee-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 15px;
padding: 25px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.employee-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(233, 69, 96, 0.2);
border-color: #e94560;
}
.employee-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.employee-name {
font-size: 1.4rem;
color: #e94560;
margin-bottom: 5px;
}
.employee-position {
color: #aaa;
font-size: 1rem;
}
.employee-number {
background: #e94560;
padding: 5px 12px;
border-radius: 20px;
font-size: 0.85rem;
font-weight: bold;
}
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
}
.info-item {
padding: 10px;
background: rgba(255, 255, 255, 0.03);
border-radius: 8px;
}
.info-label {
font-size: 0.75rem;
color: #888;
text-transform: uppercase;
margin-bottom: 5px;
}
.info-value {
font-size: 0.95rem;
color: #eee;
}
.highlight-1class {
background: rgba(255, 193, 7, 0.2) !important;
border-left: 3px solid #ffc107;
}
.highlight-11class {
background: rgba(76, 175, 80, 0.2) !important;
border-left: 3px solid #4caf50;
}
.children-section {
margin-top: 15px;
padding: 15px;
background: rgba(255, 255, 255, 0.03);
border-radius: 10px;
}
.children-section h4 {
color: #e94560;
margin-bottom: 10px;
font-size: 1rem;
}
.child-item {
padding: 8px;
margin-bottom: 8px;
background: rgba(255, 255, 255, 0.05);
border-radius: 5px;
font-size: 0.9rem;
}
.vacation-section {
margin-top: 15px;
padding: 15px;
background: rgba(233, 69, 96, 0.1);
border-radius: 10px;
border: 1px solid rgba(233, 69, 96, 0.3);
}
.vacation-section h4 {
color: #e94560;
margin-bottom: 10px;
font-size: 1rem;
}
.vacation-item {
padding: 8px;
margin-bottom: 8px;
background: rgba(255, 255, 255, 0.05);
border-radius: 5px;
font-size: 0.9rem;
display: flex;
justify-content: space-between;
}
.location-badge {
display: inline-block;
background: rgba(33, 150, 243, 0.2);
color: #2196f3;
padding: 5px 10px;
border-radius: 5px;
font-size: 0.85rem;
margin-top: 10px;
}
.no-results {
text-align: center;
padding: 50px;
color: #888;
font-size: 1.2rem;
grid-column: 1 / -1;
}
@media (max-width: 768px) {
.employees-grid {
grid-template-columns: 1fr;
}
.info-grid {
grid-template-columns: 1fr;
}
.filters {
flex-direction: column;
}
.filter-group {
width: 100%;
}
.filter-group input,
.filter-group select {
width: 100%;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>📋 Карточки сотрудников СОК-1 СД</h1>
<p>Внутренняя система учёта кадров</p>
</header>
<div class="filters">
<div class="filter-group">
<label>🔍 Поиск</label>
<input type="text" id="searchInput" placeholder="ФИО, должность, телефон...">
</div>
<div class="filter-group">
<label>📍 Дислокация</label>
<select id="locationFilter">
<option value="">Все</option>
</select>
</div>
<div class="filter-group">
<label>👶 Дети до 14 лет</label>
<select id="childrenFilter">
<option value="">Все</option>
<option value="has-children">Есть дети до 14</option>
<option value="1class">1 класс (6-7 лет)</option>
<option value="11class">11 класс (17-18 лет)</option>
</select>
</div>
<div class="filter-group">
<label>📊 Стаж</label>
<select id="experienceFilter">
<option value="">Все</option>
<option value="0-3">До 3 лет</option>
<option value="3-10">3-10 лет</option>
<option value="10+">10+ лет</option>
</select>
</div>
<div class="filter-group">
<label>🏠 Семейное</label>
<select id="familyFilter">
<option value="">Все</option>
<option value="married">Женат/Замужем</option>
<option value="single">Не женат/Не замужем</option>
</select>
</div>
</div>
<div class="stats">
<div class="stat-card">
<h3 id="totalEmployees">0</h3>
<p>Всего сотрудников</p>
</div>
<div class="stat-card">
<h3 id="withChildren">0</h3>
<p>С детьми до 14 лет</p>
</div>
<div class="stat-card">
<h3 id="firstGraders">0</h3>
<p>Дети в 1 класс</p>
</div>
<div class="stat-card">
<h3 id="eleventhGraders">0</h3>
<p>Выпускники 11 класс</p>
</div>
</div>
<div class="employees-grid" id="employeesGrid">
</div>
</div>
<script>
const employees = [
{
id: 1,
tabNumber: "001234",
fullName: "Иванов Иван Иванович",
birthDate: "15.03.1985",
age: 41,
position: "Старший тренер",
familyStatus: "Женат",
children: [
{ name: "Иванова Анна", age: 7, school: "1 класс" },
{ name: "Иванов Пётр", age: 15, school: "9 класс" }
],
address: "г. Алматы, ул. Абая 123, кв. 45",
phone: "+7 (777) 123-45-67",
experience: "12 лет",
experienceYears: 12,
vacations: [
{ start: "01.06.2025", end: "14.06.2025" },
{ start: "01.12.2025", end: "14.12.2025" }
],
location: "Главный корпус"
},
{
id: 2,
tabNumber: "001235",
fullName: "Петрова Мария Сергеевна",
birthDate: "22.07.1990",
age: 36,
position: "Инструктор по фитнесу",
familyStatus: "Замужем",
children: [
{ name: "Петров Артём", age: 6, school: "1 класс" },
{ name: "Петрова Елена", age: 3, school: "Детский сад" },
{ name: "Петров Дмитрий", age: 18, school: "11 класс" }
],
address: "г. Алматы, пр. Достык 45, кв. 12",
phone: "+7 (777) 234-56-78",
experience: "8 лет",
experienceYears: 8,
vacations: [
{ start: "15.07.2025", end: "28.07.2025" }
],
location: "Фитнес-зал"
},
{
id: 3,
tabNumber: "001236",
fullName: "Сидоров Алексей Петрович",
birthDate: "10.11.1978",
age: 47,
position: "Директор СОК-1",
familyStatus: "Женат",
children: [
{ name: "Сидорова Ольга", age: 20, school: "ВУЗ" }
],
address: "г. Алматы, ул. Казыбек би 78, кв. 90",
phone: "+7 (777) 345-67-89",
experience: "22 года",
experienceYears: 22,
vacations: [
{ start: "10.05.2025", end: "24.05.2025" },
{ start: "10.11.2025", end: "24.11.2025" }
],
location: "Администрация"
},
{
id: 4,
tabNumber: "001237",
fullName: "Ахметова Гульнара Ерлановна",
birthDate: "05.04.1995",
age: 31,
position: "Администратор",
familyStatus: "Не замужем",
children: [],
address: "г. Алматы, ул. Сатпаева 22, кв. 156",
phone: "+7 (777) 456-78-90",
experience: "4 года",
experienceYears: 4,
vacations: [
{ start: "20.08.2025", end: "02.09.2025" }
],
location: "Ресепшн"
},
{
id: 5,
tabNumber: "001238",
fullName: "Козлов Дмитрий Александрович",
birthDate: "18.09.1988",
age: 37,
position: "Тренер по плаванию",
familyStatus: "Женат",
children: [
{ name: "Козлов Максим", age: 7, school: "1 класс" },
{ name: "Козлова Дарья", age: 5, school: "Детский сад" }
],
address: "г. Алматы, ул. Байтурсынова 55, кв. 78",
phone: "+7 (777) 567-89-01",
experience: "10 лет",
experienceYears: 10,
vacations: [
{ start: "05.06.2025", end: "18.06.2025" },
{ start: "05.12.2025", end: "18.12.2025" }
],
location: "Бассейн"
},
{
id: 6,
tabNumber: "001239",
fullName: "Омаров Ержан Болатович",
birthDate: "30.01.1982",
age: 44,
position: "Завхоз",
familyStatus: "Женат",
children: [
{ name: "Омаров Асет", age: 17, school: "11 класс" },
{ name: "Омарова Зарина", age: 12, school: "6 класс" }
],
address: "г. Алматы, ул. Толе би 101, кв. 34",
phone: "+7 (777) 678-90-12",
experience: "15 лет",
experienceYears: 15,
vacations: [
{ start: "15.09.2025", end: "28.09.2025" }
],
location: "Хозяйственный отдел"
}
];
function calculateAge(birthDate) {
const today = new Date();
const birth = new Date(birthDate.split('.').reverse().join('-'));
let age = today.getFullYear() - birth.getFullYear();
const monthDiff = today.getMonth() - birth.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
age--;
}
return age;
}
function renderEmployees(data) {
const grid = document.getElementById('employeesGrid');
grid.innerHTML = '';
if (data.length === 0) {
grid.innerHTML = '<div class="no-results">😕 Сотрудники не найдены</div>';
return;
}
data.forEach(emp => {
const childrenUnder14 = emp.children.filter(c => c.age < 14);
const firstGraders = emp.children.filter(c => c.age >= 6 && c.age <= 7);
const eleventhGraders = emp.children.filter(c => c.age >= 17 && c.age <= 18);
let childrenHtml = '';
if (emp.children.length > 0) {
childrenHtml = '<div class="children-section"><h4>👶 Дети (' + emp.children.length + ')</h4>';
emp.children.forEach(child => {
let childClass = '';
if (child.age >= 6 && child.age <= 7) {
childClass = 'highlight-1class';
} else if (child.age >= 17 && child.age <= 18) {
childClass = 'highlight-11class';
}
childrenHtml += '<div class="child-item ' + childClass + '">' +
child.name + ' (' + child.age + ' лет, ' + child.school + ')';
if (child.age >= 6 && child.age <= 7) {
childrenHtml += ' <strong>🔔 1 класс</strong>';
} else if (child.age >= 17 && child.age <= 18) {
childrenHtml += ' <strong>🎓 Выпускник</strong>';
}
childrenHtml += '</div>';
});
childrenHtml += '</div>';
}
let vacationHtml = '';
if (emp.vacations.length > 0) {
vacationHtml = '<div class="vacation-section"><h4>🏖 Отпуска 2025</h4>';
emp.vacations.forEach(vac => {
vacationHtml += '<div class="vacation-item"><span>📅 ' + vac.start + ' — ' + vac.end + '</span></div>';
});
vacationHtml += '</div>';
}
const card = document.createElement('div');
card.className = 'employee-card';
card.innerHTML = `
<div class="employee-header">
<div>
<div class="employee-name">${emp.fullName}</div>
<div class="employee-position">${emp.position}</div>
</div>
<div class="employee-number">№ ${emp.tabNumber}</div>
</div>
<div class="info-grid">
<div class="info-item">
<div class="info-label">Дата рождения</div>
<div class="info-value">${emp.birthDate} (${emp.age} лет)</div>
</div>
<div class="info-item">
<div class="info-label">Семейное положение</div>
<div class="info-value">${emp.familyStatus}</div>
</div>
<div class="info-item">
<div class="info-label">Стаж работы</div>
<div class="info-value">${emp.experience}</div>
</div>
<div class="info-item">
<div class="info-label">Телефон</div>
<div class="info-value">${emp.phone}</div>
</div>
<div class="info-item" style="grid-column: 1 / -1;">
<div class="info-label">Адрес</div>
<div class="info-value">${emp.address}</div>
</div>
</div>
${childrenHtml}
${vacationHtml}
<div class="location-badge">📍 ${emp.location}</div>
`;
grid.appendChild(card);
});
}
function updateStats(data) {
const total = data.length;
const withChildren = data.filter(e => e.children.some(c => c.age < 14)).length;
const firstGraders = data.filter(e => e.children.some(c => c.age >= 6 && c.age <= 7)).length;
const eleventhGraders = data.filter(e => e.children.some(c => c.age >= 17 && c.age <= 18)).length;
document.getElementById('totalEmployees').textContent = total;
document.getElementById('withChildren').textContent = withChildren;
document.getElementById('firstGraders').textContent = firstGraders;
document.getElementById('eleventhGraders').textContent = eleventhGraders;
}
function populateLocationFilter() {
const locations = [...new Set(employees.map(e => e.location))].sort();
const select = document.getElementById('locationFilter');
locations.forEach(loc => {
const option = document.createElement('option');
option.value = loc;
option.textContent = loc;
select.appendChild(option);
});
}
function filterEmployees() {
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
const location = document.getElementById('locationFilter').value;
const childrenFilter = document.getElementById('childrenFilter').value;
const experienceFilter = document.getElementById('experienceFilter').value;
const familyFilter = document.getElementById('familyFilter').value;
let filtered = employees.filter(emp => {
const matchSearch = emp.fullName.toLowerCase().includes(searchTerm) ||
emp.position.toLowerCase().includes(searchTerm) ||
emp.phone.includes(searchTerm) ||
emp.tabNumber.includes(searchTerm);
const matchLocation = !location || emp.location === location;
let matchChildren = true;
if (childrenFilter === 'has-children') {
matchChildren = emp.children.some(c => c.age < 14);
} else if (childrenFilter === '1class') {
matchChildren = emp.children.some(c => c.age >= 6 && c.age <= 7);
} else if (childrenFilter === '11class') {
matchChildren = emp.children.some(c => c.age >= 17 && c.age <= 18);
}
let matchExperience = true;
if (experienceFilter === '0-3') {
matchExperience = emp.experienceYears < 3;
} else if (experienceFilter === '3-10') {
matchExperience = emp.experienceYears >= 3 && emp.experienceYears < 10;
} else if (experienceFilter === '10+') {
matchExperience = emp.experienceYears >= 10;
}
let matchFamily = true;
if (familyFilter === 'married') {
matchFamily = emp.familyStatus.includes('Женат') || emp.familyStatus.includes('Замужем');
} else if (familyFilter === 'single') {
matchFamily = !matchFamily;
}
return matchSearch && matchLocation && matchChildren && matchExperience && matchFamily;
});
renderEmployees(filtered);
updateStats(filtered);
}
document.getElementById('searchInput').addEventListener('input', filterEmployees);
document.getElementById('locationFilter').addEventListener('change', filterEmployees);
document.getElementById('childrenFilter').addEventListener('change', filterEmployees);
document.getElementById('experienceFilter').addEventListener('change', filterEmployees);
document.getElementById('familyFilter').addEventListener('change', filterEmployees);
populateLocationFilter();
renderEmployees(employees);
updateStats(employees);
</script>
</body>
</html>