shtat-sok-employees/index.html

689 lines
25 KiB
HTML
Raw 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: #f5f7fa;
min-height: 100vh;
color: #333;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
header {
background: linear-gradient(135deg, #0066cc 0%, #0052a3 100%);
padding: 25px 30px;
margin-bottom: 30px;
box-shadow: 0 2px 10px rgba(0, 102, 204, 0.2);
border-bottom: 3px solid #00a0e3;
}
header h1 {
color: #fff;
font-size: 1.8rem;
margin-bottom: 5px;
font-weight: 600;
}
header p {
color: #e6f0ff;
font-size: 0.95rem;
}
.filters {
background: #fff;
padding: 20px;
border-radius: 4px;
margin-bottom: 25px;
display: flex;
flex-wrap: wrap;
gap: 15px;
align-items: center;
border: 1px solid #e0e6ed;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.filter-group {
display: flex;
flex-direction: column;
gap: 6px;
}
.filter-group label {
font-size: 0.8rem;
color: #555;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.filter-group input,
.filter-group select {
padding: 10px 14px;
border: 1px solid #d0d9e2;
border-radius: 4px;
background: #fff;
color: #333;
font-size: 0.95rem;
transition: border-color 0.2s;
}
.filter-group input:focus,
.filter-group select:focus {
outline: none;
border-color: #0066cc;
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 25px;
}
.stat-card {
background: #fff;
padding: 20px;
border-radius: 4px;
text-align: center;
border-left: 4px solid #0066cc;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.stat-card h3 {
font-size: 2.2rem;
margin-bottom: 5px;
color: #0066cc;
font-weight: 700;
}
.stat-card p {
font-size: 0.85rem;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.employees-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
gap: 20px;
}
.employee-card {
background: #fff;
border-radius: 4px;
padding: 22px;
border: 1px solid #e0e6ed;
transition: all 0.2s;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.employee-card:hover {
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
border-color: #0066cc;
}
.employee-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 18px;
padding-bottom: 15px;
border-bottom: 2px solid #e0e6ed;
}
.employee-name {
font-size: 1.3rem;
color: #0066cc;
margin-bottom: 6px;
font-weight: 600;
}
.employee-position {
color: #666;
font-size: 0.95rem;
font-weight: 500;
}
.employee-number {
background: #0066cc;
color: #fff;
padding: 6px 14px;
border-radius: 4px;
font-size: 0.85rem;
font-weight: 600;
}
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.info-item {
padding: 12px;
background: #f8fafc;
border-radius: 4px;
border: 1px solid #eef2f6;
}
.info-label {
font-size: 0.7rem;
color: #8898aa;
text-transform: uppercase;
letter-spacing: 0.8px;
margin-bottom: 6px;
font-weight: 600;
}
.info-value {
font-size: 0.95rem;
color: #333;
font-weight: 500;
}
.highlight-1class {
background: #fff8e6 !important;
border-left: 3px solid #f0ad4e;
}
.highlight-11class {
background: #e8f5e9 !important;
border-left: 3px solid #4caf50;
}
.children-section {
margin-top: 18px;
padding: 15px;
background: #f8fafc;
border-radius: 4px;
border: 1px solid #eef2f6;
}
.children-section h4 {
color: #0066cc;
margin-bottom: 12px;
font-size: 0.95rem;
font-weight: 600;
}
.child-item {
padding: 10px;
margin-bottom: 8px;
background: #fff;
border-radius: 4px;
font-size: 0.9rem;
border: 1px solid #eef2f6;
}
.vacation-section {
margin-top: 18px;
padding: 15px;
background: #e8f4fd;
border-radius: 4px;
border: 1px solid #b3d9f2;
}
.vacation-section h4 {
color: #0066cc;
margin-bottom: 12px;
font-size: 0.95rem;
font-weight: 600;
}
.vacation-item {
padding: 10px;
margin-bottom: 8px;
background: #fff;
border-radius: 4px;
font-size: 0.9rem;
display: flex;
justify-content: space-between;
border: 1px solid #eef2f6;
}
.location-badge {
display: inline-block;
background: #e8f4fd;
color: #0066cc;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.85rem;
font-weight: 500;
margin-top: 15px;
border: 1px solid #b3d9f2;
}
.no-results {
text-align: center;
padding: 60px;
color: #8898aa;
font-size: 1.1rem;
grid-column: 1 / -1;
background: #fff;
border-radius: 4px;
border: 1px solid #e0e6ed;
}
@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%;
}
header h1 {
font-size: 1.4rem;
}
}
</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>