Karmashek commited on
Commit
580c960
·
verified ·
1 Parent(s): c3740d5

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +1279 -18
  3. prompts.txt +1 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Project To1
3
- emoji: 🌍
4
- colorFrom: red
5
- colorTo: yellow
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: project-to1
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1280 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
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/chart.js"></script>
10
+ <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
11
+ <style>
12
+ .sidebar {
13
+ transition: all 0.3s ease;
14
+ }
15
+ .sidebar.collapsed {
16
+ width: 70px;
17
+ }
18
+ .sidebar.collapsed .sidebar-text {
19
+ display: none;
20
+ }
21
+ .main-content {
22
+ transition: all 0.3s ease;
23
+ }
24
+ .equipment-card:hover {
25
+ transform: translateY(-5px);
26
+ box-shadow: 0 10px 20px rgba(0,0,0,0.1);
27
+ }
28
+ .notification-badge {
29
+ position: absolute;
30
+ top: -5px;
31
+ right: -5px;
32
+ }
33
+ .calendar-day.has-event {
34
+ background-color: #EFF6FF;
35
+ }
36
+ .calendar-day.event-due {
37
+ background-color: #FEE2E2;
38
+ }
39
+ .calendar-day.event-completed {
40
+ background-color: #D1FAE5;
41
+ }
42
+ </style>
43
+ </head>
44
+ <body class="bg-gray-50">
45
+ <div class="flex h-screen overflow-hidden">
46
+ <!-- Sidebar -->
47
+ <div class="sidebar bg-blue-800 text-white w-64 flex flex-col">
48
+ <div class="p-4 flex items-center justify-between border-b border-blue-700">
49
+ <div class="flex items-center">
50
+ <i class="fas fa-cogs text-2xl mr-3"></i>
51
+ <span class="sidebar-text text-xl font-bold">MES System</span>
52
+ </div>
53
+ <button id="toggleSidebar" class="text-white hover:text-blue-200">
54
+ <i class="fas fa-bars"></i>
55
+ </button>
56
+ </div>
57
+ <div class="flex-1 overflow-y-auto">
58
+ <nav class="p-4">
59
+ <div class="mb-6">
60
+ <p class="sidebar-text uppercase text-xs font-semibold text-blue-300 mb-2">Основное</p>
61
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg bg-blue-700 text-white mb-2">
62
+ <i class="fas fa-tachometer-alt mr-3"></i>
63
+ <span class="sidebar-text">Главная</span>
64
+ </a>
65
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
66
+ <i class="fas fa-calendar-alt mr-3"></i>
67
+ <span class="sidebar-text">График ТО</span>
68
+ <span class="ml-auto bg-red-500 text-white text-xs font-bold px-2 py-1 rounded-full">3</span>
69
+ </a>
70
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
71
+ <i class="fas fa-tools mr-3"></i>
72
+ <span class="sidebar-text">Оборудование</span>
73
+ </a>
74
+ </div>
75
+ <div class="mb-6">
76
+ <p class="sidebar-text uppercase text-xs font-semibold text-blue-300 mb-2">Учет</p>
77
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
78
+ <i class="fas fa-wrench mr-3"></i>
79
+ <span class="sidebar-text">Ремонтные работы</span>
80
+ </a>
81
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
82
+ <i class="fas fa-clipboard-check mr-3"></i>
83
+ <span class="sidebar-text">Техническое обслуживание</span>
84
+ </a>
85
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
86
+ <i class="fas fa-chart-line mr-3"></i>
87
+ <span class="sidebar-text">Отчеты</span>
88
+ </a>
89
+ </div>
90
+ <div class="mb-6">
91
+ <p class="sidebar-text uppercase text-xs font-semibold text-blue-300 mb-2">Настройки</p>
92
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
93
+ <i class="fas fa-bell mr-3"></i>
94
+ <span class="sidebar-text">Оповещения</span>
95
+ </a>
96
+ <a href="#" class="flex items-center py-2 px-3 rounded-lg hover:bg-blue-700 text-white mb-2">
97
+ <i class="fas fa-users-cog mr-3"></i>
98
+ <span class="sidebar-text">Пользователи</span>
99
+ </a>
100
+ </div>
101
+ </nav>
102
+ </div>
103
+ <div class="p-4 border-t border-blue-700">
104
+ <div class="flex items-center">
105
+ <img src="https://randomuser.me/api/portraits/men/32.jpg" alt="User" class="w-10 h-10 rounded-full mr-3">
106
+ <div class="sidebar-text">
107
+ <p class="font-medium">Иван Петров</p>
108
+ <p class="text-xs text-blue-300">Администратор</p>
109
+ </div>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <!-- Main Content -->
115
+ <div class="main-content flex-1 overflow-auto">
116
+ <!-- Header -->
117
+ <header class="bg-white shadow-sm py-4 px-6 flex items-center justify-between">
118
+ <h1 class="text-2xl font-bold text-gray-800">Главная панель</h1>
119
+ <div class="flex items-center space-x-4">
120
+ <div class="relative">
121
+ <button class="p-2 rounded-full hover:bg-gray-100 relative">
122
+ <i class="fas fa-bell text-gray-600"></i>
123
+ <span class="notification-badge bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">5</span>
124
+ </button>
125
+ </div>
126
+ <div class="relative">
127
+ <input type="text" placeholder="Поиск..." class="pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
128
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
129
+ </div>
130
+ </div>
131
+ </header>
132
+
133
+ <!-- Dashboard Content -->
134
+ <div class="p-6">
135
+ <!-- Stats Cards -->
136
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
137
+ <div class="bg-white rounded-lg shadow p-6">
138
+ <div class="flex items-center">
139
+ <div class="p-3 rounded-full bg-blue-100 text-blue-600 mr-4">
140
+ <i class="fas fa-tools text-xl"></i>
141
+ </div>
142
+ <div>
143
+ <p class="text-sm text-gray-500">Всего оборудования</p>
144
+ <h3 class="text-2xl font-bold">42</h3>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ <div class="bg-white rounded-lg shadow p-6">
149
+ <div class="flex items-center">
150
+ <div class="p-3 rounded-full bg-green-100 text-green-600 mr-4">
151
+ <i class="fas fa-check-circle text-xl"></i>
152
+ </div>
153
+ <div>
154
+ <p class="text-sm text-gray-500">Выполнено ТО</p>
155
+ <h3 class="text-2xl font-bold">28</h3>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ <div class="bg-white rounded-lg shadow p-6">
160
+ <div class="flex items-center">
161
+ <div class="p-3 rounded-full bg-yellow-100 text-yellow-600 mr-4">
162
+ <i class="fas fa-exclamation-triangle text-xl"></i>
163
+ </div>
164
+ <div>
165
+ <p class="text-sm text-gray-500">Просрочено ТО</p>
166
+ <h3 class="text-2xl font-bold">3</h3>
167
+ </div>
168
+ </div>
169
+ </div>
170
+ <div class="bg-white rounded-lg shadow p-6">
171
+ <div class="flex items-center">
172
+ <div class="p-3 rounded-full bg-red-100 text-red-600 mr-4">
173
+ <i class="fas fa-wrench text-xl"></i>
174
+ </div>
175
+ <div>
176
+ <p class="text-sm text-gray-500">Текущие ремонты</p>
177
+ <h3 class="text-2xl font-bold">5</h3>
178
+ </div>
179
+ </div>
180
+ </div>
181
+ </div>
182
+
183
+ <!-- Equipment and Calendar -->
184
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
185
+ <!-- Equipment List -->
186
+ <div class="lg:col-span-2 bg-white rounded-lg shadow overflow-hidden">
187
+ <div class="p-4 border-b flex justify-between items-center">
188
+ <h2 class="text-lg font-semibold">Оборудование</h2>
189
+ <button onclick="openAddEquipmentModal()" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center">
190
+ <i class="fas fa-plus mr-2"></i> Добавить
191
+ </button>
192
+ </div>
193
+ <div class="overflow-x-auto">
194
+ <table class="min-w-full divide-y divide-gray-200">
195
+ <thead class="bg-gray-50">
196
+ <tr>
197
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
198
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Название</th>
199
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Тип</th>
200
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Статус</th>
201
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Последнее ТО</th>
202
+ <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Действия</th>
203
+ </tr>
204
+ </thead>
205
+ <tbody class="bg-white divide-y divide-gray-200" id="equipmentTableBody">
206
+ <!-- Equipment rows will be added here by JavaScript -->
207
+ </tbody>
208
+ </table>
209
+ </div>
210
+ </div>
211
+
212
+ <!-- Maintenance Calendar -->
213
+ <div class="bg-white rounded-lg shadow overflow-hidden">
214
+ <div class="p-4 border-b">
215
+ <h2 class="text-lg font-semibold">График ТО</h2>
216
+ </div>
217
+ <div class="p-4">
218
+ <div class="flex justify-between items-center mb-4">
219
+ <h3 class="font-medium">Июнь 2023</h3>
220
+ <div class="flex space-x-2">
221
+ <button class="p-2 rounded-full hover:bg-gray-100">
222
+ <i class="fas fa-chevron-left"></i>
223
+ </button>
224
+ <button class="p-2 rounded-full hover:bg-gray-100">
225
+ <i class="fas fa-chevron-right"></i>
226
+ </button>
227
+ </div>
228
+ </div>
229
+ <div class="grid grid-cols-7 gap-1 mb-2">
230
+ <div class="text-center text-xs font-medium text-gray-500">Пн</div>
231
+ <div class="text-center text-xs font-medium text-gray-500">Вт</div>
232
+ <div class="text-center text-xs font-medium text-gray-500">Ср</div>
233
+ <div class="text-center text-xs font-medium text-gray-500">Чт</div>
234
+ <div class="text-center text-xs font-medium text-gray-500">Пт</div>
235
+ <div class="text-center text-xs font-medium text-gray-500">Сб</div>
236
+ <div class="text-center text-xs font-medium text-gray-500">Вс</div>
237
+ </div>
238
+ <div class="grid grid-cols-7 gap-1" id="calendarDays">
239
+ <!-- Calendar days will be added here by JavaScript -->
240
+ </div>
241
+ </div>
242
+ <div class="p-4 border-t">
243
+ <h3 class="font-medium mb-2">Предстоящие ТО</h3>
244
+ <div class="space-y-3" id="upcomingMaintenance">
245
+ <!-- Upcoming maintenance items will be added here by JavaScript -->
246
+ </div>
247
+ </div>
248
+ </div>
249
+ </div>
250
+
251
+ <!-- Charts -->
252
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
253
+ <div class="bg-white rounded-lg shadow p-6">
254
+ <div class="flex justify-between items-center mb-4">
255
+ <h2 class="text-lg font-semibold">Статистика ТО по месяцам</h2>
256
+ <select class="border rounded-lg px-3 py-1 text-sm">
257
+ <option>2023</option>
258
+ <option>2022</option>
259
+ <option>2021</option>
260
+ </select>
261
+ </div>
262
+ <canvas id="maintenanceChart" height="250"></canvas>
263
+ </div>
264
+ <div class="bg-white rounded-lg shadow p-6">
265
+ <div class="flex justify-between items-center mb-4">
266
+ <h2 class="text-lg font-semibold">Статус оборудования</h2>
267
+ </div>
268
+ <canvas id="equipmentStatusChart" height="250"></canvas>
269
+ </div>
270
+ </div>
271
+ </div>
272
+ </div>
273
+ </div>
274
+
275
+ <!-- Add Equipment Modal -->
276
+ <div id="addEquipmentModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
277
+ <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl">
278
+ <div class="p-4 border-b flex justify-between items-center">
279
+ <h3 class="text-lg font-semibold">Добавить новое оборудование</h3>
280
+ <button onclick="closeAddEquipmentModal()" class="text-gray-500 hover:text-gray-700">
281
+ <i class="fas fa-times"></i>
282
+ </button>
283
+ </div>
284
+ <div class="p-6">
285
+ <form id="equipmentForm">
286
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
287
+ <div>
288
+ <label class="block text-sm font-medium text-gray-700 mb-1">Название оборудования</label>
289
+ <input type="text" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
290
+ </div>
291
+ <div>
292
+ <label class="block text-sm font-medium text-gray-700 mb-1">Тип оборудования</label>
293
+ <select class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
294
+ <option value="">Выберите тип</option>
295
+ <option>Станок</option>
296
+ <option>Конвейер</option>
297
+ <option>Компрессор</option>
298
+ <option>Генератор</option>
299
+ <option>Насос</option>
300
+ </select>
301
+ </div>
302
+ <div>
303
+ <label class="block text-sm font-medium text-gray-700 mb-1">Серийный номер</label>
304
+ <input type="text" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
305
+ </div>
306
+ <div>
307
+ <label class="block text-sm font-medium text-gray-700 mb-1">Инвентарный номер</label>
308
+ <input type="text" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
309
+ </div>
310
+ <div>
311
+ <label class="block text-sm font-medium text-gray-700 mb-1">Дата ввода в эксплуатацию</label>
312
+ <input type="date" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
313
+ </div>
314
+ <div>
315
+ <label class="block text-sm font-medium text-gray-700 mb-1">Периодичность ТО (дни)</label>
316
+ <input type="number" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" value="30" required>
317
+ </div>
318
+ <div class="md:col-span-2">
319
+ <label class="block text-sm font-medium text-gray-700 mb-1">Описание</label>
320
+ <textarea class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" rows="3"></textarea>
321
+ </div>
322
+ </div>
323
+ </form>
324
+ </div>
325
+ <div class="p-4 border-t flex justify-end space-x-3">
326
+ <button onclick="closeAddEquipmentModal()" class="px-4 py-2 border rounded-lg hover:bg-gray-50">Отмена</button>
327
+ <button onclick="saveEquipment()" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Сохранить</button>
328
+ </div>
329
+ </div>
330
+ </div>
331
+
332
+ <!-- Edit Equipment Modal -->
333
+ <div id="editEquipmentModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
334
+ <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl">
335
+ <div class="p-4 border-b flex justify-between items-center">
336
+ <h3 class="text-lg font-semibold">Редактировать оборудование</h3>
337
+ <button onclick="closeEditEquipmentModal()" class="text-gray-500 hover:text-gray-700">
338
+ <i class="fas fa-times"></i>
339
+ </button>
340
+ </div>
341
+ <div class="p-6">
342
+ <form id="editEquipmentForm">
343
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
344
+ <div>
345
+ <label class="block text-sm font-medium text-gray-700 mb-1">Название оборудования</label>
346
+ <input type="text" id="editName" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
347
+ </div>
348
+ <div>
349
+ <label class="block text-sm font-medium text-gray-700 mb-1">Тип оборудования</label>
350
+ <select id="editType" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
351
+ <option value="">Выберите тип</option>
352
+ <option>Станок</option>
353
+ <option>Конвейер</option>
354
+ <option>Компрессор</option>
355
+ <option>Генератор</option>
356
+ <option>Насос</option>
357
+ </select>
358
+ </div>
359
+ <div>
360
+ <label class="block text-sm font-medium text-gray-700 mb-1">Серийный номер</label>
361
+ <input type="text" id="editSerial" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
362
+ </div>
363
+ <div>
364
+ <label class="block text-sm font-medium text-gray-700 mb-1">Инвентарный номер</label>
365
+ <input type="text" id="editInventory" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
366
+ </div>
367
+ <div>
368
+ <label class="block text-sm font-medium text-gray-700 mb-1">Дата ввода в эксплуатацию</label>
369
+ <input type="date" id="editCommissionDate" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
370
+ </div>
371
+ <div>
372
+ <label class="block text-sm font-medium text-gray-700 mb-1">Периодичность ТО (дни)</label>
373
+ <input type="number" id="editMaintenanceInterval" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" required>
374
+ </div>
375
+ <div class="md:col-span-2">
376
+ <label class="block text-sm font-medium text-gray-700 mb-1">Описание</label>
377
+ <textarea id="editDescription" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" rows="3"></textarea>
378
+ </div>
379
+ </div>
380
+ </form>
381
+ </div>
382
+ <div class="p-4 border-t flex justify-end space-x-3">
383
+ <button onclick="closeEditEquipmentModal()" class="px-4 py-2 border rounded-lg hover:bg-gray-50">Отмена</button>
384
+ <button onclick="updateEquipment()" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Сохранить изменения</button>
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ <!-- Maintenance Details Modal -->
390
+ <div id="maintenanceModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
391
+ <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl">
392
+ <div class="p-4 border-b flex justify-between items-center">
393
+ <h3 class="text-lg font-semibold">Техническое обслуживание</h3>
394
+ <button onclick="closeMaintenanceModal()" class="text-gray-500 hover:text-gray-700">
395
+ <i class="fas fa-times"></i>
396
+ </button>
397
+ </div>
398
+ <div class="p-6">
399
+ <div class="mb-6">
400
+ <h4 class="font-medium text-lg mb-2" id="maintenanceEquipmentName">Токарный станок CNC-2000</h4>
401
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
402
+ <div>
403
+ <p class="text-sm text-gray-500">Дата последнего ТО</p>
404
+ <p class="font-medium" id="lastMaintenanceDate">15.05.2023</p>
405
+ </div>
406
+ <div>
407
+ <p class="text-sm text-gray-500">Следующее ТО</p>
408
+ <p class="font-medium" id="nextMaintenanceDate">15.06.2023</p>
409
+ </div>
410
+ <div>
411
+ <p class="text-sm text-gray-500">Статус</p>
412
+ <p class="font-medium">
413
+ <span id="maintenanceStatus" class="px-2 py-1 rounded-full text-xs font-semibold bg-yellow-100 text-yellow-800">Запланировано</span>
414
+ </p>
415
+ </div>
416
+ <div>
417
+ <p class="text-sm text-gray-500">Ответственный</p>
418
+ <p class="font-medium" id="maintenanceResponsible">Иванов А.П.</p>
419
+ </div>
420
+ </div>
421
+ </div>
422
+ <div class="mb-6">
423
+ <h4 class="font-medium mb-3">Запланировать ТО</h4>
424
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
425
+ <div>
426
+ <label class="block text-sm font-medium text-gray-700 mb-1">Дата ТО</label>
427
+ <input type="date" id="maintenanceDate" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
428
+ </div>
429
+ <div>
430
+ <label class="block text-sm font-medium text-gray-700 mb-1">Ответственный</label>
431
+ <select id="maintenanceResponsibleSelect" class="w-full border rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500">
432
+ <option>Иванов А.П.</option>
433
+ <option>Петров И.С.</option>
434
+ <option>Сидоров В.М.</option>
435
+ <option>Кузнецова Е.В.</option>
436
+ </select>
437
+ </div>
438
+ </div>
439
+ </div>
440
+ <div>
441
+ <h4 class="font-medium mb-3">Выполненные работы</h4>
442
+ <div class="space-y-4" id="maintenanceTasks">
443
+ <!-- Maintenance tasks will be added here by JavaScript -->
444
+ </div>
445
+ <button onclick="addMaintenanceTask()" class="mt-4 flex items-center text-blue-600 hover:text-blue-800">
446
+ <i class="fas fa-plus mr-2"></i> Добавить работу
447
+ </button>
448
+ </div>
449
+ </div>
450
+ <div class="p-4 border-t flex justify-between">
451
+ <button onclick="markMaintenanceAsCompleted()" class="px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700">
452
+ <i class="fas fa-check mr-2"></i> Завершить ТО
453
+ </button>
454
+ <div class="flex space-x-3">
455
+ <button onclick="closeMaintenanceModal()" class="px-4 py-2 border rounded-lg hover:bg-gray-50">Отмена</button>
456
+ <button onclick="saveMaintenance()" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Сохранить</button>
457
+ </div>
458
+ </div>
459
+ </div>
460
+ </div>
461
+
462
+ <script>
463
+ // Sample data for equipment
464
+ const equipmentData = [
465
+ {
466
+ id: 1,
467
+ name: "Токарный станок CNC-2000",
468
+ type: "Станок",
469
+ serial: "CNC2000-001",
470
+ inventory: "INV-1001",
471
+ status: "active",
472
+ lastMaintenance: "2023-05-15",
473
+ nextMaintenance: "2023-06-15",
474
+ maintenanceInterval: 30,
475
+ description: "Токарный станок с ЧПУ, производитель XYZ Corp."
476
+ },
477
+ {
478
+ id: 2,
479
+ name: "Конвейерная линия A-12",
480
+ type: "Конвейер",
481
+ serial: "CONV-A12-045",
482
+ inventory: "INV-1042",
483
+ status: "active",
484
+ lastMaintenance: "2023-05-20",
485
+ nextMaintenance: "2023-06-20",
486
+ maintenanceInterval: 30,
487
+ description: "Конвейерная линия для сборки продукции"
488
+ },
489
+ {
490
+ id: 3,
491
+ name: "Воздушный компрессор V-50",
492
+ type: "Компрессор",
493
+ serial: "COMP-V50-112",
494
+ inventory: "INV-1078",
495
+ status: "maintenance",
496
+ lastMaintenance: "2023-04-10",
497
+ nextMaintenance: "2023-06-10",
498
+ maintenanceInterval: 60,
499
+ description: "Промышленный воздушный компрессор"
500
+ },
501
+ {
502
+ id: 4,
503
+ name: "Генератор DG-5000",
504
+ type: "Генератор",
505
+ serial: "GEN-DG5000-008",
506
+ inventory: "INV-1123",
507
+ status: "active",
508
+ lastMaintenance: "2023-05-01",
509
+ nextMaintenance: "2023-08-01",
510
+ maintenanceInterval: 90,
511
+ description: "Дизельный генератор резервного питания"
512
+ },
513
+ {
514
+ id: 5,
515
+ name: "Насосный агрегат NP-200",
516
+ type: "Насос",
517
+ serial: "PUMP-NP200-156",
518
+ inventory: "INV-1156",
519
+ status: "repair",
520
+ lastMaintenance: "2023-03-15",
521
+ nextMaintenance: "2023-06-15",
522
+ maintenanceInterval: 90,
523
+ description: "Центробежный насос для перекачки жидкостей"
524
+ }
525
+ ];
526
+
527
+ // Sample data for maintenance events
528
+ const maintenanceEvents = [
529
+ { equipmentId: 1, date: "2023-06-15", status: "planned", responsible: "Иванов А.П." },
530
+ { equipmentId: 2, date: "2023-06-20", status: "planned", responsible: "Петров И.С." },
531
+ { equipmentId: 3, date: "2023-06-10", status: "overdue", responsible: "Сидоров В.М." },
532
+ { equipmentId: 4, date: "2023-08-01", status: "planned", responsible: "Кузнецова Е.В." },
533
+ { equipmentId: 5, date: "2023-06-15", status: "planned", responsible: "Иванов А.П." },
534
+ { equipmentId: 1, date: "2023-05-15", status: "completed", responsible: "Иванов А.П." },
535
+ { equipmentId: 2, date: "2023-05-20", status: "completed", responsible: "Петров И.С." },
536
+ { equipmentId: 3, date: "2023-04-10", status: "completed", responsible: "Сидоров В.М." },
537
+ { equipmentId: 4, date: "2023-05-01", status: "completed", responsible: "Кузнецова Е.В." },
538
+ { equipmentId: 5, date: "2023-03-15", status: "completed", responsible: "Иванов А.П." }
539
+ ];
540
+
541
+ // Sample data for maintenance tasks
542
+ const maintenanceTasks = {
543
+ 1: [
544
+ { id: 1, description: "Проверка и регулировка ЧПУ", completed: true },
545
+ { id: 2, description: "Смазка направляющих", completed: true },
546
+ { id: 3, description: "Замена фильтров", completed: true }
547
+ ],
548
+ 2: [
549
+ { id: 1, description: "Проверка натяжения ленты", completed: true },
550
+ { id: 2, description: "Смазка роликов", completed: true }
551
+ ],
552
+ 3: [
553
+ { id: 1, description: "Замена масла", completed: true },
554
+ { id: 2, description: "Проверка давления", completed: false }
555
+ ]
556
+ };
557
+
558
+ // Current month and year for calendar
559
+ const currentDate = new Date();
560
+ const currentMonth = currentDate.getMonth();
561
+ const currentYear = currentDate.getFullYear();
562
+
563
+ // DOM elements
564
+ const equipmentTableBody = document.getElementById('equipmentTableBody');
565
+ const calendarDays = document.getElementById('calendarDays');
566
+ const upcomingMaintenance = document.getElementById('upcomingMaintenance');
567
+ let currentEditingEquipmentId = null;
568
+
569
+ // Initialize the application
570
+ function init() {
571
+ renderEquipmentTable();
572
+ renderCalendar();
573
+ renderUpcomingMaintenance();
574
+ initCharts();
575
+ setupEventListeners();
576
+ }
577
+
578
+ // Render equipment table
579
+ function renderEquipmentTable() {
580
+ equipmentTableBody.innerHTML = '';
581
+
582
+ equipmentData.forEach(equipment => {
583
+ const row = document.createElement('tr');
584
+
585
+ // Determine status badge color
586
+ let statusBadge = '';
587
+ if (equipment.status === 'active') {
588
+ statusBadge = '<span class="px-2 py-1 rounded-full text-xs font-semibold bg-green-100 text-green-800">Активно</span>';
589
+ } else if (equipment.status === 'maintenance') {
590
+ statusBadge = '<span class="px-2 py-1 rounded-full text-xs font-semibold bg-yellow-100 text-yellow-800">ТО</span>';
591
+ } else if (equipment.status === 'repair') {
592
+ statusBadge = '<span class="px-2 py-1 rounded-full text-xs font-semibold bg-red-100 text-red-800">Ремонт</span>';
593
+ }
594
+
595
+ // Format dates
596
+ const lastMaintenanceDate = formatDate(equipment.lastMaintenance);
597
+ const nextMaintenanceDate = formatDate(equipment.nextMaintenance);
598
+
599
+ row.innerHTML = `
600
+ <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${equipment.id}</td>
601
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${equipment.name}</td>
602
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${equipment.type}</td>
603
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${statusBadge}</td>
604
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${lastMaintenanceDate}</td>
605
+ <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
606
+ <button onclick="openMaintenanceModal(${equipment.id})" class="text-blue-600 hover:text-blue-900 mr-3">
607
+ <i class="fas fa-calendar-alt"></i>
608
+ </button>
609
+ <button onclick="openEditEquipmentModal(${equipment.id})" class="text-yellow-600 hover:text-yellow-900 mr-3">
610
+ <i class="fas fa-edit"></i>
611
+ </button>
612
+ <button onclick="deleteEquipment(${equipment.id})" class="text-red-600 hover:text-red-900">
613
+ <i class="fas fa-trash"></i>
614
+ </button>
615
+ </td>
616
+ `;
617
+
618
+ equipmentTableBody.appendChild(row);
619
+ });
620
+ }
621
+
622
+ // Render calendar
623
+ function renderCalendar() {
624
+ calendarDays.innerHTML = '';
625
+
626
+ // Get first day of month and total days in month
627
+ const firstDay = new Date(currentYear, currentMonth, 1).getDay();
628
+ const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
629
+
630
+ // Adjust for Monday as first day (0 = Sunday, 1 = Monday, etc.)
631
+ const adjustedFirstDay = firstDay === 0 ? 6 : firstDay - 1;
632
+
633
+ // Add empty cells for days before the first day of the month
634
+ for (let i = 0; i < adjustedFirstDay; i++) {
635
+ const emptyCell = document.createElement('div');
636
+ emptyCell.className = 'h-10';
637
+ calendarDays.appendChild(emptyCell);
638
+ }
639
+
640
+ // Add cells for each day of the month
641
+ for (let day = 1; day <= daysInMonth; day++) {
642
+ const dateStr = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
643
+ const cell = document.createElement('div');
644
+ cell.className = 'h-10 flex items-center justify-center border rounded cursor-pointer calendar-day';
645
+
646
+ // Check if this day has any maintenance events
647
+ const events = maintenanceEvents.filter(event => event.date === dateStr);
648
+
649
+ if (events.length > 0) {
650
+ const statuses = events.map(event => event.status);
651
+
652
+ if (statuses.includes('overdue')) {
653
+ cell.classList.add('event-due');
654
+ } else if (statuses.includes('completed')) {
655
+ cell.classList.add('event-completed');
656
+ } else {
657
+ cell.classList.add('has-event');
658
+ }
659
+
660
+ // Add tooltip with equipment names
661
+ const equipmentNames = events.map(event => {
662
+ const equipment = equipmentData.find(e => e.id === event.equipmentId);
663
+ return equipment ? equipment.name : '';
664
+ }).filter(name => name !== '');
665
+
666
+ cell.setAttribute('title', equipmentNames.join('\n'));
667
+ }
668
+
669
+ cell.textContent = day;
670
+ cell.onclick = () => showDayEvents(day);
671
+ calendarDays.appendChild(cell);
672
+ }
673
+ }
674
+
675
+ // Render upcoming maintenance
676
+ function renderUpcomingMaintenance() {
677
+ upcomingMaintenance.innerHTML = '';
678
+
679
+ // Get today's date in YYYY-MM-DD format
680
+ const today = new Date().toISOString().split('T')[0];
681
+
682
+ // Filter maintenance events that are upcoming or overdue
683
+ const upcomingEvents = maintenanceEvents.filter(event => {
684
+ return event.status !== 'completed' && (event.date >= today || event.status === 'overdue');
685
+ }).sort((a, b) => new Date(a.date) - new Date(b.date));
686
+
687
+ // Limit to 5 events
688
+ const eventsToShow = upcomingEvents.slice(0, 5);
689
+
690
+ eventsToShow.forEach(event => {
691
+ const equipment = equipmentData.find(e => e.id === event.equipmentId);
692
+ if (!equipment) return;
693
+
694
+ const eventDate = new Date(event.date);
695
+ const today = new Date();
696
+ const diffTime = eventDate - today;
697
+ const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
698
+
699
+ let daysText = '';
700
+ if (diffDays < 0) {
701
+ daysText = `<span class="text-red-500">Просрочено на ${Math.abs(diffDays)} дн.</span>`;
702
+ } else if (diffDays === 0) {
703
+ daysText = '<span class="text-yellow-600">Сегодня</span>';
704
+ } else {
705
+ daysText = `Через ${diffDays} дн.`;
706
+ }
707
+
708
+ const eventElement = document.createElement('div');
709
+ eventElement.className = 'p-3 border rounded-lg hover:bg-gray-50 cursor-pointer';
710
+ eventElement.onclick = () => openMaintenanceModal(event.equipmentId);
711
+
712
+ eventElement.innerHTML = `
713
+ <div class="flex justify-between items-start">
714
+ <div>
715
+ <h4 class="font-medium">${equipment.name}</h4>
716
+ <p class="text-sm text-gray-500">${equipment.type}</p>
717
+ </div>
718
+ <span class="text-sm">${daysText}</span>
719
+ </div>
720
+ <div class="mt-2 flex justify-between items-center">
721
+ <span class="text-sm">${formatDate(event.date)}</span>
722
+ <span class="text-sm">${event.responsible}</span>
723
+ </div>
724
+ `;
725
+
726
+ upcomingMaintenance.appendChild(eventElement);
727
+ });
728
+
729
+ if (eventsToShow.length === 0) {
730
+ upcomingMaintenance.innerHTML = '<p class="text-gray-500 text-center py-4">Нет предстоящих ТО</p>';
731
+ }
732
+ }
733
+
734
+ // Initialize charts
735
+ function initCharts() {
736
+ // Maintenance by month chart
737
+ const maintenanceCtx = document.getElementById('maintenanceChart').getContext('2d');
738
+ new Chart(maintenanceCtx, {
739
+ type: 'bar',
740
+ data: {
741
+ labels: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],
742
+ datasets: [
743
+ {
744
+ label: 'Запланировано',
745
+ data: [5, 7, 6, 8, 10, 12, 8, 7, 6, 9, 7, 5],
746
+ backgroundColor: '#3B82F6',
747
+ },
748
+ {
749
+ label: 'Выполнено',
750
+ data: [5, 6, 5, 7, 9, 8, 6, 5, 4, 7, 5, 4],
751
+ backgroundColor: '#10B981',
752
+ },
753
+ {
754
+ label: 'Просрочено',
755
+ data: [0, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 1],
756
+ backgroundColor: '#EF4444',
757
+ }
758
+ ]
759
+ },
760
+ options: {
761
+ responsive: true,
762
+ plugins: {
763
+ legend: {
764
+ position: 'top',
765
+ },
766
+ },
767
+ scales: {
768
+ x: {
769
+ stacked: false,
770
+ },
771
+ y: {
772
+ stacked: false,
773
+ beginAtZero: true
774
+ }
775
+ }
776
+ }
777
+ });
778
+
779
+ // Equipment status chart
780
+ const statusCtx = document.getElementById('equipmentStatusChart').getContext('2d');
781
+ new Chart(statusCtx, {
782
+ type: 'doughnut',
783
+ data: {
784
+ labels: ['Активно', 'На ТО', 'В ремонте', 'Резерв'],
785
+ datasets: [{
786
+ data: [32, 5, 3, 2],
787
+ backgroundColor: [
788
+ '#10B981',
789
+ '#F59E0B',
790
+ '#EF4444',
791
+ '#6B7280'
792
+ ],
793
+ borderWidth: 0
794
+ }]
795
+ },
796
+ options: {
797
+ responsive: true,
798
+ plugins: {
799
+ legend: {
800
+ position: 'right',
801
+ }
802
+ }
803
+ }
804
+ });
805
+ }
806
+
807
+ // Setup event listeners
808
+ function setupEventListeners() {
809
+ // Toggle sidebar
810
+ document.getElementById('toggleSidebar').addEventListener('click', () => {
811
+ document.querySelector('.sidebar').classList.toggle('collapsed');
812
+ document.querySelector('.main-content').classList.toggle('ml-16');
813
+ document.querySelector('.main-content').classList.toggle('ml-64');
814
+ });
815
+ }
816
+
817
+ // Format date to DD.MM.YYYY
818
+ function formatDate(dateString) {
819
+ if (!dateString) return '';
820
+ const date = new Date(dateString);
821
+ const day = String(date.getDate()).padStart(2, '0');
822
+ const month = String(date.getMonth() + 1).padStart(2, '0');
823
+ const year = date.getFullYear();
824
+ return `${day}.${month}.${year}`;
825
+ }
826
+
827
+ // Show events for a specific day
828
+ function showDayEvents(day) {
829
+ const dateStr = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
830
+ const events = maintenanceEvents.filter(event => event.date === dateStr);
831
+
832
+ if (events.length === 0) {
833
+ Swal.fire({
834
+ title: `${day} ${getMonthName(currentMonth)} ${currentYear}`,
835
+ text: 'На этот день не запланировано ТО',
836
+ icon: 'info'
837
+ });
838
+ return;
839
+ }
840
+
841
+ let html = `<h3 class="font-bold mb-2">${day} ${getMonthName(currentMonth)} ${currentYear}</h3>`;
842
+ html += '<div class="space-y-2">';
843
+
844
+ events.forEach(event => {
845
+ const equipment = equipmentData.find(e => e.id === event.equipmentId);
846
+ if (!equipment) return;
847
+
848
+ let statusBadge = '';
849
+ if (event.status === 'planned') {
850
+ statusBadge = '<span class="px-2 py-1 rounded-full text-xs font-semibold bg-blue-100 text-blue-800">Запланировано</span>';
851
+ } else if (event.status === 'overdue') {
852
+ statusBadge = '<span class="px-2 py-1 rounded-full text-xs font-semibold bg-red-100 text-red-800">Просрочено</span>';
853
+ } else if (event.status === 'completed') {
854
+ statusBadge = '<span class="px-2 py-1 rounded-full text-xs font-semibold bg-green-100 text-green-800">Выполнено</span>';
855
+ }
856
+
857
+ html += `
858
+ <div class="p-3 border rounded-lg">
859
+ <div class="flex justify-between items-center mb-1">
860
+ <h4 class="font-medium">${equipment.name}</h4>
861
+ ${statusBadge}
862
+ </div>
863
+ <p class="text-sm text-gray-600">${equipment.type}</p>
864
+ <p class="text-sm mt-1">Ответственный: ${event.responsible}</p>
865
+ <button onclick="openMaintenanceModal(${equipment.id})" class="mt-2 text-sm text-blue-600 hover:text-blue-800">
866
+ Подробнее <i class="fas fa-chevron-right ml-1"></i>
867
+ </button>
868
+ </div>
869
+ `;
870
+ });
871
+
872
+ html += '</div>';
873
+
874
+ Swal.fire({
875
+ html: html,
876
+ showConfirmButton: false,
877
+ width: '500px'
878
+ });
879
+ }
880
+
881
+ // Get month name
882
+ function getMonthName(monthIndex) {
883
+ const months = [
884
+ 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь',
885
+ 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'
886
+ ];
887
+ return months[monthIndex];
888
+ }
889
+
890
+ // Open add equipment modal
891
+ function openAddEquipmentModal() {
892
+ document.getElementById('addEquipmentModal').classList.remove('hidden');
893
+ }
894
+
895
+ // Close add equipment modal
896
+ function closeAddEquipmentModal() {
897
+ document.getElementById('addEquipmentModal').classList.add('hidden');
898
+ document.getElementById('equipmentForm').reset();
899
+ }
900
+
901
+ // Save new equipment
902
+ function saveEquipment() {
903
+ const form = document.getElementById('equipmentForm');
904
+ const formData = new FormData(form);
905
+
906
+ // Validate form
907
+ let isValid = true;
908
+ form.querySelectorAll('[required]').forEach(input => {
909
+ if (!input.value) {
910
+ input.classList.add('border-red-500');
911
+ isValid = false;
912
+ } else {
913
+ input.classList.remove('border-red-500');
914
+ }
915
+ });
916
+
917
+ if (!isValid) {
918
+ Swal.fire({
919
+ title: 'Ошибка',
920
+ text: 'Пожалуйста, заполните все обязательные поля',
921
+ icon: 'error'
922
+ });
923
+ return;
924
+ }
925
+
926
+ // Create new equipment object
927
+ const newEquipment = {
928
+ id: equipmentData.length + 1,
929
+ name: formData.get('name'),
930
+ type: formData.get('type'),
931
+ serial: formData.get('serial'),
932
+ inventory: formData.get('inventory'),
933
+ status: 'active',
934
+ lastMaintenance: '',
935
+ nextMaintenance: calculateNextMaintenanceDate(formData.get('commissionDate'), formData.get('maintenanceInterval')),
936
+ maintenanceInterval: parseInt(formData.get('maintenanceInterval')),
937
+ description: formData.get('description')
938
+ };
939
+
940
+ // Add to equipment data
941
+ equipmentData.push(newEquipment);
942
+
943
+ // Close modal and refresh table
944
+ closeAddEquipmentModal();
945
+ renderEquipmentTable();
946
+
947
+ Swal.fire({
948
+ title: 'Успешно',
949
+ text: 'Оборудование добавлено',
950
+ icon: 'success'
951
+ });
952
+ }
953
+
954
+ // Calculate next maintenance date
955
+ function calculateNextMaintenanceDate(commissionDate, intervalDays) {
956
+ if (!commissionDate) return '';
957
+
958
+ const intervalMs = parseInt(intervalDays) * 24 * 60 * 60 * 1000;
959
+ const nextDate = new Date(new Date(commissionDate).getTime() + intervalMs);
960
+ return nextDate.toISOString().split('T')[0];
961
+ }
962
+
963
+ // Open edit equipment modal
964
+ function openEditEquipmentModal(id) {
965
+ const equipment = equipmentData.find(e => e.id === id);
966
+ if (!equipment) return;
967
+
968
+ currentEditingEquipmentId = id;
969
+
970
+ document.getElementById('editName').value = equipment.name;
971
+ document.getElementById('editType').value = equipment.type;
972
+ document.getElementById('editSerial').value = equipment.serial;
973
+ document.getElementById('editInventory').value = equipment.inventory;
974
+ document.getElementById('editCommissionDate').value = equipment.commissionDate || '';
975
+ document.getElementById('editMaintenanceInterval').value = equipment.maintenanceInterval;
976
+ document.getElementById('editDescription').value = equipment.description || '';
977
+
978
+ document.getElementById('editEquipmentModal').classList.remove('hidden');
979
+ }
980
+
981
+ // Close edit equipment modal
982
+ function closeEditEquipmentModal() {
983
+ document.getElementById('editEquipmentModal').classList.add('hidden');
984
+ currentEditingEquipmentId = null;
985
+ }
986
+
987
+ // Update equipment
988
+ function updateEquipment() {
989
+ const equipment = equipmentData.find(e => e.id === currentEditingEquipmentId);
990
+ if (!equipment) return;
991
+
992
+ equipment.name = document.getElementById('editName').value;
993
+ equipment.type = document.getElementById('editType').value;
994
+ equipment.serial = document.getElementById('editSerial').value;
995
+ equipment.inventory = document.getElementById('editInventory').value;
996
+ equipment.commissionDate = document.getElementById('editCommissionDate').value;
997
+ equipment.maintenanceInterval = parseInt(document.getElementById('editMaintenanceInterval').value);
998
+ equipment.description = document.getElementById('editDescription').value;
999
+
1000
+ // Close modal and refresh table
1001
+ closeEditEquipmentModal();
1002
+ renderEquipmentTable();
1003
+
1004
+ Swal.fire({
1005
+ title: 'Успешно',
1006
+ text: 'Изменения сохранены',
1007
+ icon: 'success'
1008
+ });
1009
+ }
1010
+
1011
+ // Delete equipment
1012
+ function deleteEquipment(id) {
1013
+ Swal.fire({
1014
+ title: 'Удалить оборудование?',
1015
+ text: 'Вы уверены, что хотите удалить это оборудование? Это действие нельзя отменить.',
1016
+ icon: 'warning',
1017
+ showCancelButton: true,
1018
+ confirmButtonText: 'Да, удалить',
1019
+ cancelButtonText: 'Отмена'
1020
+ }).then((result) => {
1021
+ if (result.isConfirmed) {
1022
+ const index = equipmentData.findIndex(e => e.id === id);
1023
+ if (index !== -1) {
1024
+ equipmentData.splice(index, 1);
1025
+ renderEquipmentTable();
1026
+
1027
+ Swal.fire(
1028
+ 'Удалено!',
1029
+ 'Оборудование было удалено.',
1030
+ 'success'
1031
+ );
1032
+ }
1033
+ }
1034
+ });
1035
+ }
1036
+
1037
+ // Open maintenance modal
1038
+ function openMaintenanceModal(equipmentId) {
1039
+ const equipment = equipmentData.find(e => e.id === equipmentId);
1040
+ if (!equipment) return;
1041
+
1042
+ // Find current maintenance event
1043
+ const maintenanceEvent = maintenanceEvents.find(event =>
1044
+ event.equipmentId === equipmentId &&
1045
+ (event.status === 'planned' || event.status === 'overdue')
1046
+ );
1047
+
1048
+ // Set equipment info
1049
+ document.getElementById('maintenanceEquipmentName').textContent = equipment.name;
1050
+ document.getElementById('lastMaintenanceDate').textContent = formatDate(equipment.lastMaintenance);
1051
+ document.getElementById('nextMaintenanceDate').textContent = formatDate(equipment.nextMaintenance);
1052
+
1053
+ // Set status
1054
+ const statusElement = document.getElementById('maintenanceStatus');
1055
+ statusElement.textContent = maintenanceEvent ?
1056
+ (maintenanceEvent.status === 'overdue' ? 'Просрочено' : 'Запланировано') :
1057
+ 'Не запланировано';
1058
+
1059
+ statusElement.className = 'px-2 py-1 rounded-full text-xs font-semibold ' +
1060
+ (maintenanceEvent ?
1061
+ (maintenanceEvent.status === 'overdue' ? 'bg-red-100 text-red-800' : 'bg-blue-100 text-blue-800') :
1062
+ 'bg-gray-100 text-gray-800');
1063
+
1064
+ // Set responsible
1065
+ document.getElementById('maintenanceResponsible').textContent =
1066
+ maintenanceEvent ? maintenanceEvent.responsible : 'Не назначен';
1067
+
1068
+ if (maintenanceEvent) {
1069
+ document.getElementById('maintenanceDate').value = maintenanceEvent.date;
1070
+ document.getElementById('maintenanceResponsibleSelect').value = maintenanceEvent.responsible;
1071
+ } else {
1072
+ document.getElementById('maintenanceDate').value = equipment.nextMaintenance;
1073
+ document.getElementById('maintenanceResponsibleSelect').value = 'Иванов А.П.';
1074
+ }
1075
+
1076
+ // Render tasks
1077
+ renderMaintenanceTasks(equipmentId);
1078
+
1079
+ document.getElementById('maintenanceModal').classList.remove('hidden');
1080
+ }
1081
+
1082
+ // Close maintenance modal
1083
+ function closeMaintenanceModal() {
1084
+ document.getElementById('maintenanceModal').classList.add('hidden');
1085
+ }
1086
+
1087
+ // Render maintenance tasks
1088
+ function renderMaintenanceTasks(equipmentId) {
1089
+ const tasksContainer = document.getElementById('maintenanceTasks');
1090
+ tasksContainer.innerHTML = '';
1091
+
1092
+ const tasks = maintenanceTasks[equipmentId] || [];
1093
+
1094
+ tasks.forEach((task, index) => {
1095
+ const taskElement = document.createElement('div');
1096
+ taskElement.className = 'flex items-start';
1097
+
1098
+ taskElement.innerHTML = `
1099
+ <input type="checkbox" ${task.completed ? 'checked' : ''}
1100
+ onchange="toggleTaskCompletion(${equipmentId}, ${task.id})"
1101
+ class="mt-1 mr-3 h-5 w-5 rounded border-gray-300 text-blue-600 focus:ring-blue-500">
1102
+ <div class="flex-1">
1103
+ <p class="${task.completed ? 'line-through text-gray-500' : ''}">${task.description}</p>
1104
+ <button onclick="removeTask(${equipmentId}, ${task.id})" class="mt-1 text-sm text-red-600 hover:text-red-800">
1105
+ <i class="fas fa-trash mr-1"></i> Удалить
1106
+ </button>
1107
+ </div>
1108
+ `;
1109
+
1110
+ tasksContainer.appendChild(taskElement);
1111
+ });
1112
+
1113
+ if (tasks.length === 0) {
1114
+ tasksContainer.innerHTML = '<p class="text-gray-500 text-center py-4">Нет добавленных работ</p>';
1115
+ }
1116
+ }
1117
+
1118
+ // Add maintenance task
1119
+ function addMaintenanceTask() {
1120
+ const equipmentId = currentEditingEquipmentId;
1121
+ if (!equipmentId) return;
1122
+
1123
+ Swal.fire({
1124
+ title: 'Добавить работу',
1125
+ input: 'text',
1126
+ inputLabel: 'Описание работы',
1127
+ inputPlaceholder: 'Введите описание работы...',
1128
+ showCancelButton: true,
1129
+ confirmButtonText: 'Добавить',
1130
+ cancelButtonText: 'Отмена',
1131
+ inputValidator: (value) => {
1132
+ if (!value) {
1133
+ return 'Пожалуйста, введите описание работы';
1134
+ }
1135
+ }
1136
+ }).then((result) => {
1137
+ if (result.isConfirmed) {
1138
+ if (!maintenanceTasks[equipmentId]) {
1139
+ maintenanceTasks[equipmentId] = [];
1140
+ }
1141
+
1142
+ const newTask = {
1143
+ id: maintenanceTasks[equipmentId].length + 1,
1144
+ description: result.value,
1145
+ completed: false
1146
+ };
1147
+
1148
+ maintenanceTasks[equipmentId].push(newTask);
1149
+ renderMaintenanceTasks(equipmentId);
1150
+ }
1151
+ });
1152
+ }
1153
+
1154
+ // Remove task
1155
+ function removeTask(equipmentId, taskId) {
1156
+ if (!maintenanceTasks[equipmentId]) return;
1157
+
1158
+ const index = maintenanceTasks[equipmentId].findIndex(t => t.id === taskId);
1159
+ if (index !== -1) {
1160
+ maintenanceTasks[equipmentId].splice(index, 1);
1161
+ renderMaintenanceTasks(equipmentId);
1162
+ }
1163
+ }
1164
+
1165
+ // Toggle task completion
1166
+ function toggleTaskCompletion(equipmentId, taskId) {
1167
+ if (!maintenanceTasks[equipmentId]) return;
1168
+
1169
+ const task = maintenanceTasks[equipmentId].find(t => t.id === taskId);
1170
+ if (task) {
1171
+ task.completed = !task.completed;
1172
+ renderMaintenanceTasks(equipmentId);
1173
+ }
1174
+ }
1175
+
1176
+ // Save maintenance
1177
+ function saveMaintenance() {
1178
+ const equipmentId = currentEditingEquipmentId;
1179
+ if (!equipmentId) return;
1180
+
1181
+ const equipment = equipmentData.find(e => e.id === equipmentId);
1182
+ if (!equipment) return;
1183
+
1184
+ const date = document.getElementById('maintenanceDate').value;
1185
+ const responsible = document.getElementById('maintenanceResponsibleSelect').value;
1186
+
1187
+ if (!date) {
1188
+ Swal.fire({
1189
+ title: 'Ошибка',
1190
+ text: 'Пожалуйста, укажите дату ТО',
1191
+ icon: 'error'
1192
+ });
1193
+ return;
1194
+ }
1195
+
1196
+ // Find or create maintenance event
1197
+ let maintenanceEvent = maintenanceEvents.find(event =>
1198
+ event.equipmentId === equipmentId &&
1199
+ (event.status === 'planned' || event.status === 'overdue')
1200
+ );
1201
+
1202
+ if (maintenanceEvent) {
1203
+ maintenanceEvent.date = date;
1204
+ maintenanceEvent.responsible = responsible;
1205
+ } else {
1206
+ maintenanceEvent = {
1207
+ equipmentId,
1208
+ date,
1209
+ status: 'planned',
1210
+ responsible
1211
+ };
1212
+ maintenanceEvents.push(maintenanceEvent);
1213
+ }
1214
+
1215
+ // Update equipment's next maintenance date
1216
+ equipment.nextMaintenance = date;
1217
+
1218
+ closeMaintenanceModal();
1219
+ renderEquipmentTable();
1220
+ renderCalendar();
1221
+ renderUpcomingMaintenance();
1222
+
1223
+ Swal.fire({
1224
+ title: 'Успешно',
1225
+ text: 'График ТО обновлен',
1226
+ icon: 'success'
1227
+ });
1228
+ }
1229
+
1230
+ // Mark maintenance as completed
1231
+ function markMaintenanceAsCompleted() {
1232
+ const equipmentId = currentEditingEquipmentId;
1233
+ if (!equipmentId) return;
1234
+
1235
+ const equipment = equipmentData.find(e => e.id === equipmentId);
1236
+ if (!equipment) return;
1237
+
1238
+ // Find current maintenance event
1239
+ const maintenanceEvent = maintenanceEvents.find(event =>
1240
+ event.equipmentId === equipmentId &&
1241
+ (event.status === 'planned' || event.status === 'overdue')
1242
+ );
1243
+
1244
+ if (maintenanceEvent) {
1245
+ maintenanceEvent.status = 'completed';
1246
+
1247
+ // Update equipment's last maintenance date
1248
+ equipment.lastMaintenance = maintenanceEvent.date;
1249
+
1250
+ // Calculate next maintenance date
1251
+ const nextDate = new Date(new Date(maintenanceEvent.date).getTime() +
1252
+ equipment.maintenanceInterval * 24 * 60 * 60 * 1000);
1253
+ equipment.nextMaintenance = nextDate.toISOString().split('T')[0];
1254
+
1255
+ // Add new planned maintenance event
1256
+ maintenanceEvents.push({
1257
+ equipmentId,
1258
+ date: equipment.nextMaintenance,
1259
+ status: 'planned',
1260
+ responsible: maintenanceEvent.responsible
1261
+ });
1262
+
1263
+ closeMaintenanceModal();
1264
+ renderEquipmentTable();
1265
+ renderCalendar();
1266
+ renderUpcomingMaintenance();
1267
+
1268
+ Swal.fire({
1269
+ title: 'Успешно',
1270
+ text: 'ТО отмечено как выполненное',
1271
+ icon: 'success'
1272
+ });
1273
+ }
1274
+ }
1275
+
1276
+ // Initialize the app when DOM is loaded
1277
+ document.addEventListener('DOMContentLoaded', init);
1278
+ </script>
1279
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Karmashek/project-to1" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1280
  </html>
prompts.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ Нужен рабочий сайт на потобие системы MES для учета ремонтных работ и проведения ТО, с графиком ТО и возможностью редактирования и добавления нового оборудования, и редактирования и системой оповещение по графику ТО