Karmashek commited on
Commit
ca8db7a
·
verified ·
1 Parent(s): ac1db79

Upload 4 files

Browse files
Files changed (4) hide show
  1. Js.js.txt +5 -0
  2. index.html.html +524 -0
  3. js1.js.txt +1 -0
  4. js2.js.txt +1 -0
Js.js.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ const response = await fetch("http://your-api/login", {
2
+ method: "POST",
3
+ headers: { "Content-Type": "application/json" },
4
+ body: JSON.stringify({ username, password })
5
+ });
index.html.html ADDED
@@ -0,0 +1,524 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="ru">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>MES System</title>
7
+ <script src="https://cdn.tailwindcss.com "></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css "/>
9
+ <script src="https://cdn.jsdelivr.net/npm/sweetalert2 @11"></script>
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js "></script>
11
+ <style>
12
+ .notification-badge {
13
+ position: absolute;
14
+ top: 0; right: 0;
15
+ font-size: 0.625rem; line-height: 1.25rem;
16
+ width: 1.25rem; height: 1.25rem;
17
+ display: flex; align-items: center; justify-content: center;
18
+ border-radius: 9999px;
19
+ }
20
+ .has-event:hover { background-color: #BFDBFE !important; }
21
+ .hidden { display: none; }
22
+ </style>
23
+ </head>
24
+ <body class="bg-gray-100 text-gray-900">
25
+
26
+ <!-- Login Modal -->
27
+ <div id="loginModal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center z-50">
28
+ <div class="bg-white rounded-lg shadow-lg w-full max-w-md p-6">
29
+ <h3 class="text-xl font-bold mb-4">Вход в систему</h3>
30
+ <form id="loginForm" class="space-y-4">
31
+ <input type="text" id="loginUsername" placeholder="Имя пользователя" required class="w-full px-4 py-2 border rounded-lg">
32
+ <input type="password" id="loginPassword" placeholder="Пароль" required class="w-full px-4 py-2 border rounded-lg">
33
+ <button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white py-2 rounded-lg">Войти</button>
34
+ </form>
35
+ </div>
36
+ </div>
37
+
38
+ <!-- Sidebar -->
39
+ <div id="sidebar" class="fixed top-0 left-0 h-full bg-blue-800 text-white w-64 p-4 hidden">
40
+ <div class="flex items-center justify-between mb-6">
41
+ <h1 class="text-xl font-bold">MES System</h1>
42
+ <button onclick="toggleSidebar()" class="text-white hover:text-blue-200"><i class="fas fa-bars"></i></button>
43
+ </div>
44
+
45
+ <nav>
46
+ <ul class="space-y-2">
47
+ <li><button onclick="showTab('dashboard')" class="tab-btn active w-full text-left px-4 py-2 rounded-lg bg-blue-700"><i class="fas fa-tachometer-alt mr-2"></i> Главная</button></li>
48
+ <li><button onclick="showTab('schedule')" class="tab-btn w-full text-left px-4 py-2 rounded-lg hover:bg-blue-700"><i class="fas fa-calendar-alt mr-2"></i> График ТО</button></li>
49
+ <li><button onclick="showTab('equipment')" class="tab-btn w-full text-left px-4 py-2 rounded-lg hover:bg-blue-700"><i class="fas fa-tools mr-2"></i> Оборудование</button></li>
50
+ <li><button onclick="showTab('repairs')" class="tab-btn w-full text-left px-4 py-2 rounded-lg hover:bg-blue-700"><i class="fas fa-wrench mr-2"></i> Ремонт</button></li>
51
+ <li><button onclick="showTab('maintenance')" class="tab-btn w-full text-left px-4 py-2 rounded-lg hover:bg-blue-700"><i class="fas fa-clipboard-check mr-2"></i> Техобслуживание</button></li>
52
+ <li><button onclick="showTab('reports')" class="tab-btn w-full text-left px-4 py-2 rounded-lg hover:bg-blue-700"><i class="fas fa-chart-line mr-2"></i> Отчеты</button></li>
53
+ <li><button onclick="showTab('users')" class="tab-btn w-full text-left px-4 py-2 rounded-lg hover:bg-blue-700"><i class="fas fa-users-cog mr-2"></i> Пользователи</button></li>
54
+ </ul>
55
+ </nav>
56
+ </div>
57
+
58
+ <!-- Main Content -->
59
+ <div id="mainContent" class="ml-64 p-6 min-h-screen hidden">
60
+ <!-- Header -->
61
+ <header class="bg-white shadow-sm p-4 rounded-lg mb-6 flex justify-between items-center">
62
+ <h1 id="page-title" class="text-2xl font-semibold">Главная панель</h1>
63
+ <div class="flex space-x-4">
64
+ <button class="p-2 rounded-full hover:bg-gray-100 relative">
65
+ <i class="fas fa-bell text-gray-600"></i>
66
+ <span class="notification-badge bg-red-500 text-white">3</span>
67
+ </button>
68
+ <div class="relative">
69
+ <input type="text" id="searchInput" oninput="filterEquipment()" placeholder="Поиск..." class="pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
70
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
71
+ </div>
72
+ <button onclick="logout()" class="text-red-600 hover:text-red-800">Выход</button>
73
+ </div>
74
+ </header>
75
+
76
+ <!-- Tabs -->
77
+ <div id="content" class="bg-white rounded-lg shadow p-6">
78
+
79
+ <!-- Dashboard Tab -->
80
+ <div id="dashboard" class="tab-content active">
81
+ <h2 class="text-2xl font-bold mb-6">Главная панель</h2>
82
+
83
+ <!-- Stats Cards -->
84
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
85
+ <div class="bg-white rounded-lg shadow p-6 border-l-4 border-blue-500">
86
+ <h4 class="font-medium text-gray-500">Всего оборудования</h4>
87
+ <p id="total-equipment" class="text-2xl font-bold">0</p>
88
+ </div>
89
+ <div class="bg-white rounded-lg shadow p-6 border-l-4 border-green-500">
90
+ <h4 class="font-medium text-gray-500">Выполнено ТО</h4>
91
+ <p id="completed-maintenance" class="text-2xl font-bold">0</p>
92
+ </div>
93
+ <div class="bg-white rounded-lg shadow p-6 border-l-4 border-yellow-500">
94
+ <h4 class="font-medium text-gray-500">Просрочено ТО</h4>
95
+ <p id="overdue-maintenance" class="text-2xl font-bold">0</p>
96
+ </div>
97
+ <div class="bg-white rounded-lg shadow p-6 border-l-4 border-red-500">
98
+ <h4 class="font-medium text-gray-500">Текущие ремонты</h4>
99
+ <p id="current-repairs" class="text-2xl font-bold">0</p>
100
+ </div>
101
+ </div>
102
+
103
+ <!-- Equipment Table -->
104
+ <div class="bg-white rounded-lg shadow overflow-hidden">
105
+ <div class="p-4 border-b flex justify-between items-center">
106
+ <h2 class="text-lg font-semibold">Оборудование</h2>
107
+ <button onclick="showTab('equipment')" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg">
108
+ Перейти к оборудованию
109
+ </button>
110
+ </div>
111
+ <div class="overflow-x-auto">
112
+ <table id="dashboard-table" class="min-w-full divide-y divide-gray-200">
113
+ <thead class="bg-gray-50">
114
+ <tr>
115
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">ID</th>
116
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Название</th>
117
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Статус</th>
118
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Последнее ТО</th>
119
+ </tr>
120
+ </thead>
121
+ <tbody id="dashboard-body" class="bg-white divide-y divide-gray-200"></tbody>
122
+ </table>
123
+ </div>
124
+ </div>
125
+ </div>
126
+
127
+ <!-- Equipment Tab -->
128
+ <div id="equipment" class="tab-content hidden">
129
+ <div class="mb-4 flex justify-between items-center">
130
+ <h2 class="text-2xl font-bold">Оборудование</h2>
131
+ <button onclick="openAddEquipmentModal()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center">
132
+ <i class="fas fa-plus mr-2"></i> Добавить оборудование
133
+ </button>
134
+ </div>
135
+
136
+ <div class="mb-4 flex space-x-4">
137
+ <select id="statusFilter" onchange="filterEquipment()" class="border rounded-lg px-4 py-2">
138
+ <option value="">Все статусы</option>
139
+ <option value="active">Активно</option>
140
+ <option value="maintenance">ТО</option>
141
+ <option value="repair">Ремонт</option>
142
+ </select>
143
+ <select id="typeFilter" onchange="filterEquipment()" class="border rounded-lg px-4 py-2">
144
+ <option value="">Все типы</option>
145
+ <option>Станок</option>
146
+ <option>Конвейер</option>
147
+ <option>Компрессор</option>
148
+ <option>Генератор</option>
149
+ <option>Насос</option>
150
+ </select>
151
+ <input type="text" id="inventoryFilter" oninput="filterEquipment()" placeholder="Инвентарный номер" class="border rounded-lg px-4 py-2 w-1/4">
152
+ <div class="flex items-center space-x-2">
153
+ <input type="date" id="dateFrom" oninput="filterEquipment()" class="border rounded-lg px-4 py-2">
154
+ <span>-</span>
155
+ <input type="date" id="dateTo" oninput="filterEquipment()" class="border rounded-lg px-4 py-2">
156
+ </div>
157
+ </div>
158
+
159
+ <div class="bg-white rounded-lg shadow overflow-hidden">
160
+ <div class="overflow-x-auto">
161
+ <table class="min-w-full divide-y divide-gray-200">
162
+ <thead class="bg-gray-50">
163
+ <tr>
164
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">ID</th>
165
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Название</th>
166
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Тип</th>
167
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Статус</th>
168
+ <th class="px-6 py-3 text-left text-xs uppercase tracking-wider">Действия</th>
169
+ </tr>
170
+ </thead>
171
+ <tbody id="equipment-list" class="bg-white divide-y divide-gray-200"></tbody>
172
+ </table>
173
+ </div>
174
+ </div>
175
+ </div>
176
+
177
+ <!-- Reports Tab -->
178
+ <div id="reports" class="tab-content hidden">
179
+ <h2 class="text-2xl font-bold mb-6">Отчеты</h2>
180
+ <div class="mb-4 flex justify-end space-x-4">
181
+ <button onclick="exportToExcel()" class="bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg flex items-center">
182
+ <i class="fas fa-file-pdf mr-2"></i> Экспорт в PDF
183
+ </button>
184
+ <button onclick="exportFilteredToExcel()" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg flex items-center">
185
+ <i class="fas fa-filter mr-2"></i> Экспорт с фильтром
186
+ </button>
187
+ </div>
188
+ <div class="bg-white rounded-lg shadow p-6">
189
+ <canvas id="equipmentStatusChart" width="400" height="250"></canvas>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </div>
194
+
195
+ <!-- Add Equipment Modal -->
196
+ <div id="addEquipmentModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
197
+ <div class="bg-white rounded-lg shadow-lg w-full max-w-2xl">
198
+ <div class="p-4 border-b flex justify-between items-center">
199
+ <h3 class="text-lg font-semibold">Добавить новое оборудование</h3>
200
+ <button onclick="closeAddEquipmentModal()" class="text-gray-500 hover:text-gray-700">&times;</button>
201
+ </div>
202
+ <form id="equipmentForm" class="p-6 space-y-4">
203
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
204
+ <div>
205
+ <label class="block text-sm font-medium text-gray-700 mb-1">Название</label>
206
+ <input type="text" name="name" required class="w-full border rounded-lg px-4 py-2">
207
+ </div>
208
+ <div>
209
+ <label class="block text-sm font-medium text-gray-700 mb-1">Тип</label>
210
+ <select name="type" required class="w-full border rounded-lg px-4 py-2">
211
+ <option value="">Выберите тип</option>
212
+ <option>Станок</option>
213
+ <option>Конвейер</option>
214
+ <option>Компрессор</option>
215
+ <option>Генератор</option>
216
+ <option>Насос</option>
217
+ </select>
218
+ </div>
219
+ <div>
220
+ <label class="block text-sm font-medium text-gray-700 mb-1">Серийный номер</label>
221
+ <input type="text" name="serial" required class="w-full border rounded-lg px-4 py-2">
222
+ </div>
223
+ <div>
224
+ <label class="block text-sm font-medium text-gray-700 mb-1">Инвентарный номер</label>
225
+ <input type="text" name="inventory" required class="w-full border rounded-lg px-4 py-2">
226
+ </div>
227
+ <div>
228
+ <label class="block text-sm font-medium text-gray-700 mb-1">Дата ввода в эксплуатацию</label>
229
+ <input type="date" name="commissionDate" required class="w-full border rounded-lg px-4 py-2">
230
+ </div>
231
+ <div>
232
+ <label class="block text-sm font-medium text-gray-700 mb-1">Периодичность ТО (дни)</label>
233
+ <input type="number" name="interval" required min="1" class="w-full border rounded-lg px-4 py-2">
234
+ </div>
235
+ <div class="md:col-span-2">
236
+ <label class="block text-sm font-medium text-gray-700 mb-1">Описание</label>
237
+ <textarea name="description" rows="3" class="w-full border rounded-lg px-4 py-2"></textarea>
238
+ </div>
239
+ </div>
240
+ <div class="mt-4 flex justify-end space-x-2">
241
+ <button type="button" onclick="closeAddEquipmentModal()" class="border px-4 py-2 rounded hover:bg-gray-100">Отмена</button>
242
+ <button type="button" onclick="saveEquipment()" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Сохранить</button>
243
+ </div>
244
+ </form>
245
+ </div>
246
+ </div>
247
+
248
+ <script>
249
+ // Mock API URL (replace with your backend)
250
+ const API_URL = "https://jsonplaceholder.typicode.com/posts ";
251
+ let equipmentData = [];
252
+
253
+ function saveToLocalStorage() {
254
+ localStorage.setItem("equipment", JSON.stringify(equipmentData));
255
+ }
256
+
257
+ function loadFromLocalStorage() {
258
+ const saved = localStorage.getItem("equipment");
259
+ if (saved) equipmentData = JSON.parse(saved);
260
+ }
261
+
262
+ async function login(username, password) {
263
+ // Mock auth - replace with real endpoint
264
+ const response = await fetch(`https://jsonplaceholder.typicode.com/users?email= ${username}@example.com`);
265
+ const users = await response.json();
266
+ if (users.length > 0 && password === "123456") {
267
+ localStorage.setItem("token", btoa(`${username}:${password}`));
268
+ return true;
269
+ }
270
+ return false;
271
+ }
272
+
273
+ async function logout() {
274
+ localStorage.removeItem("token");
275
+ location.reload();
276
+ }
277
+
278
+ async function fetchEquipment() {
279
+ try {
280
+ const response = await fetch(API_URL);
281
+ equipmentData = await response.json();
282
+ renderAll();
283
+ } catch (e) {
284
+ console.error("Ошибка загрузки данных:", e);
285
+ }
286
+ }
287
+
288
+ function updateDashboardStats() {
289
+ document.getElementById("total-equipment").textContent = equipmentData.length;
290
+ document.getElementById("completed-maintenance").textContent = equipmentData.filter(e => e.lastMaintenance).length;
291
+ document.getElementById("overdue-maintenance").textContent = equipmentData.filter(e => new Date(e.nextMaintenance) < new Date()).length;
292
+ document.getElementById("current-repairs").textContent = equipmentData.filter(e => e.status === "repair").length;
293
+ }
294
+
295
+ function filterEquipment() {
296
+ const status = document.getElementById("statusFilter").value;
297
+ const type = document.getElementById("typeFilter").value;
298
+ const inventory = document.getElementById("inventoryFilter").value.toLowerCase();
299
+ const dateFrom = document.getElementById("dateFrom").value;
300
+ const dateTo = document.getElementById("dateTo").value;
301
+
302
+ const tbody = document.getElementById("equipment-list");
303
+ tbody.innerHTML = '';
304
+
305
+ equipmentData.filter(eq => {
306
+ return (!status || eq.status === status) &&
307
+ (!type || eq.type === type) &&
308
+ (!inventory || eq.inventory?.toLowerCase().includes(inventory)) &&
309
+ (!dateFrom || eq.nextMaintenance >= dateFrom) &&
310
+ (!dateTo || eq.nextMaintenance <= dateTo);
311
+ }).forEach(eq => {
312
+ const row = document.createElement("tr");
313
+ row.innerHTML = `
314
+ <td class="px-6 py-4">${eq.id}</td>
315
+ <td class="px-6 py-4">${eq.name}</td>
316
+ <td class="px-6 py-4">${eq.type}</td>
317
+ <td class="px-6 py-4">
318
+ <span class="px-2 py-1 rounded-full text-xs font-semibold ${eq.status === 'active' ? 'bg-green-100 text-green-800' : eq.status === 'maintenance' ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800'}">
319
+ ${eq.status === 'active' ? 'Активно' : eq.status === 'maintenance' ? 'ТО' : 'Ремонт'}
320
+ </span>
321
+ </td>
322
+ <td class="px-6 py-4">
323
+ <button onclick="editEquipment(${eq.id})" class="text-blue-600 hover:text-blue-800 mr-3"><i class="fas fa-edit"></i></button>
324
+ <button onclick="deleteEquipment(${eq.id})" class="text-red-600 hover:text-red-800"><i class="fas fa-trash"></i></button>
325
+ </td>
326
+ `;
327
+ tbody.appendChild(row);
328
+ });
329
+ }
330
+
331
+ function formatDate(dateStr) {
332
+ if (!dateStr) return "";
333
+ const d = new Date(dateStr);
334
+ return `${d.getDate()}.${d.getMonth()+1}.${d.getFullYear()}`;
335
+ }
336
+
337
+ function calculateNextMaintenanceDate(commissionDate, intervalDays) {
338
+ if (!commissionDate) return '';
339
+ const nextDate = new Date(new Date(commissionDate).getTime() + parseInt(intervalDays)*24*60*60*1000);
340
+ return nextDate.toISOString().split('T')[0];
341
+ }
342
+
343
+ function openAddEquipmentModal() {
344
+ document.getElementById("addEquipmentModal").classList.remove("hidden");
345
+ }
346
+
347
+ function closeAddEquipmentModal() {
348
+ document.getElementById("addEquipmentModal").classList.add("hidden");
349
+ document.getElementById("equipmentForm").reset();
350
+ }
351
+
352
+ async function saveEquipment() {
353
+ const form = document.getElementById("equipmentForm");
354
+ const formData = new FormData(form);
355
+ const name = formData.get("name");
356
+ const type = formData.get("type");
357
+ const serial = formData.get("serial");
358
+ const inventory = formData.get("inventory");
359
+ const commissionDate = formData.get("commissionDate");
360
+ const interval = formData.get("interval");
361
+ const description = formData.get("description");
362
+
363
+ if (!name || !type || !serial || !inventory || !commissionDate || !interval) {
364
+ Swal.fire({ title: 'Ошибка', text: 'Заполните все обязательные поля', icon: 'error' });
365
+ return;
366
+ }
367
+
368
+ const newEq = {
369
+ name, type, serial, inventory,
370
+ status: "active",
371
+ lastMaintenance: "",
372
+ nextMaintenance: calculateNextMaintenanceDate(commissionDate, interval),
373
+ maintenanceInterval: interval,
374
+ description
375
+ };
376
+
377
+ // Simulate POST request
378
+ const response = await fetch(API_URL, {
379
+ method: "POST",
380
+ headers: { "Content-Type": "application/json" },
381
+ body: JSON.stringify(newEq)
382
+ });
383
+
384
+ if (response.ok) {
385
+ const data = await response.json();
386
+ equipmentData.push(data);
387
+ closeAddEquipmentModal();
388
+ renderAll();
389
+ Swal.fire({ title: 'Успешно', text: 'Оборудование добавлено', icon: 'success' });
390
+ } else {
391
+ Swal.fire({ title: 'Ошибка', text: 'Не удалось сохранить оборудование', icon: 'error' });
392
+ }
393
+ }
394
+
395
+ function editEquipment(id) {
396
+ window.location.href = `#edit-${id}`;
397
+ alert("Редактирование не реализовано в этом примере для упрощения");
398
+ }
399
+
400
+ async function deleteEquipment(id) {
401
+ Swal.fire({
402
+ title: 'Удалить?', text: 'Это действие нельзя отменить', icon: 'warning',
403
+ showCancelButton: true, confirmButtonText: 'Да, удалить', cancelButtonText: 'Отмена'
404
+ }).then(async result => {
405
+ if (result.isConfirmed) {
406
+ const response = await fetch(`${API_URL}/${id}`, { method: "DELETE" });
407
+ if (response.ok) {
408
+ equipmentData = equipmentData.filter(eq => eq.id !== id);
409
+ renderAll();
410
+ Swal.fire('Удалено!', 'Оборудование удалено', 'success');
411
+ }
412
+ }
413
+ });
414
+ }
415
+
416
+ function exportToExcel() {
417
+ const ws = XLSX.utils.aoa_to_sheet([
418
+ ["ID", "Название", "Тип", "Статус", "Инвента��ный номер"],
419
+ ...equipmentData.map(eq => [eq.id, eq.name, eq.type, eq.status, eq.inventory])
420
+ ]);
421
+ const wb = XLSX.utils.book_new();
422
+ XLSX.utils.book_append_sheet(wb, ws, "Оборудование");
423
+ XLSX.writeFile(wb, "equipment-report.xlsx");
424
+ }
425
+
426
+ function exportFilteredToExcel() {
427
+ const filtered = equipmentData.filter(eq => {
428
+ const status = document.getElementById("statusFilter").value;
429
+ const type = document.getElementById("typeFilter").value;
430
+ const inventory = document.getElementById("inventoryFilter").value.toLowerCase();
431
+ const dateFrom = document.getElementById("dateFrom").value;
432
+ const dateTo = document.getElementById("dateTo").value;
433
+
434
+ return (!status || eq.status === status) &&
435
+ (!type || eq.type === type) &&
436
+ (!inventory || eq.inventory?.toLowerCase().includes(inventory)) &&
437
+ (!dateFrom || eq.nextMaintenance >= dateFrom) &&
438
+ (!dateTo || eq.nextMaintenance <= dateTo);
439
+ });
440
+
441
+ const ws = XLSX.utils.aoa_to_sheet([
442
+ ["ID", "Название", "Тип", "Статус", "Инвентарный номер"],
443
+ ...filtered.map(eq => [eq.id, eq.name, eq.type, eq.status, eq.inventory])
444
+ ]);
445
+
446
+ const wb = XLSX.utils.book_new();
447
+ XLSX.utils.book_append_sheet(wb, ws, "Фильтрованное оборудование");
448
+ XLSX.writeFile(wb, "filtered-equipment.xlsx");
449
+ }
450
+
451
+ function initApp() {
452
+ const token = localStorage.getItem("token");
453
+ if (!token) {
454
+ document.getElementById("loginModal").classList.remove("hidden");
455
+ } else {
456
+ document.getElementById("loginModal").remove();
457
+ document.getElementById("mainContent").classList.remove("hidden");
458
+ document.getElementById("sidebar").classList.remove("hidden");
459
+ loadFromLocalStorage();
460
+ fetchEquipment();
461
+ }
462
+ }
463
+
464
+ document.getElementById("loginForm")?.addEventListener("submit", async function(e) {
465
+ e.preventDefault();
466
+ const username = document.getElementById("loginUsername").value;
467
+ const password = document.getElementById("loginPassword").value;
468
+
469
+ const success = await login(username, password);
470
+ if (success) {
471
+ fetchEquipment();
472
+ initCharts();
473
+ } else {
474
+ Swal.fire({ title: 'Ошибка', text: 'Неверный логин или пароль', icon: 'error' });
475
+ }
476
+ });
477
+
478
+ function renderAll() {
479
+ filterEquipment();
480
+ updateDashboardStats();
481
+ }
482
+
483
+ function initCharts() {
484
+ const statusCtx = document.getElementById('equipmentStatusChart').getContext('2d');
485
+ new Chart(statusCtx, {
486
+ type: 'doughnut',
487
+ data: {
488
+ labels: ['Активно', 'На ТО', 'В ремонте'],
489
+ datasets: [{
490
+ data: [
491
+ equipmentData.filter(e => e.status === 'active').length,
492
+ equipmentData.filter(e => e.status === 'maintenance').length,
493
+ equipmentData.filter(e => e.status === 'repair').length
494
+ ],
495
+ backgroundColor: ['#10B981','#F59E0B','#EF4444']
496
+ }]
497
+ },
498
+ options: { responsive: true, plugins: { legend: { position: 'right' } }
499
+ });
500
+ }
501
+
502
+ function toggleSidebar() {
503
+ const sidebar = document.getElementById("sidebar");
504
+ const isCollapsed = sidebar.classList.contains("collapsed");
505
+ sidebar.classList.toggle("collapsed", !isCollapsed);
506
+ document.querySelector(".ml-64").classList.toggle("ml-16", !isCollapsed);
507
+ }
508
+
509
+ function showTab(tabId) {
510
+ document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));
511
+ document.getElementById(tabId).classList.remove('hidden');
512
+ document.getElementById('page-title').innerText = tabId.charAt(0).toUpperCase() + tabId.slice(1);
513
+
514
+ document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('bg-blue-700'));
515
+ event.target.classList.add('bg-blue-700');
516
+ }
517
+
518
+ window.onload = () => {
519
+ initApp();
520
+ };
521
+ </script>
522
+
523
+ </body>
524
+ </html>
js1.js.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ if (users.length > 0 && password === "123456")
js2.js.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ const response = await fetch(`https://jsonplaceholder.typicode.com/users?email=admin @example.com`);