med-cms 1.0.0-beta.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE.txt +13 -0
  2. package/README.md +117 -0
  3. package/database/config/db-init.js +67 -53
  4. package/database/models/appointments.js +35 -20
  5. package/database/models/clinics.js +25 -13
  6. package/database/models/diseases.js +21 -13
  7. package/database/models/districts.js +55 -0
  8. package/database/models/news.js +25 -0
  9. package/database/models/user-addresses.js +21 -14
  10. package/database/models/users.js +69 -26
  11. package/database/services/admin/create-clinic.js +18 -6
  12. package/database/services/admin/db-analytics.js +42 -16
  13. package/database/services/admin/index.js +6 -6
  14. package/database/services/admin/manage-staff.js +47 -17
  15. package/database/services/doctor/conduct-exam.js +26 -20
  16. package/database/services/doctor/get-schedule.js +26 -18
  17. package/database/services/doctor/index.js +6 -6
  18. package/database/services/doctor/patient-access.js +34 -25
  19. package/database/services/patient/book-appointment.js +37 -17
  20. package/database/services/patient/calc-district.js +70 -21
  21. package/database/services/patient/get-profile.js +49 -21
  22. package/database/services/patient/index.js +5 -5
  23. package/env_init.js +55 -0
  24. package/index.d.ts +38 -24
  25. package/index.js +48 -25
  26. package/migrate-diseases.js +192 -120
  27. package/package.json +3 -3
  28. package/public/css/admin.css +80 -80
  29. package/public/css/auth.css +52 -44
  30. package/public/css/doctor.css +131 -125
  31. package/public/css/home.css +155 -0
  32. package/public/html/dashboard-admin.html +423 -101
  33. package/public/html/dashboard-doctor.html +155 -66
  34. package/public/html/dashboard-patient.html +199 -94
  35. package/public/html/home/about.html +0 -0
  36. package/public/html/home/contact.html +0 -0
  37. package/public/html/home/info.html +0 -0
  38. package/public/html/home.html +159 -0
  39. package/public/html/login.html +73 -43
  40. package/public/js/admin.js +329 -165
  41. package/public/js/auth.js +45 -41
  42. package/public/js/doctor.js +117 -103
  43. package/public/js/home.js +113 -0
  44. package/public/js/patient.js +130 -108
  45. package/server/midleware.js +33 -13
  46. package/server/permissions.js +105 -43
  47. package/server/server.js +517 -176
  48. package/README +0 -161
  49. package/test.js +0 -27
package/server/server.js CHANGED
@@ -1,75 +1,100 @@
1
- const express = require('express');
2
- const path = require('path');
3
- const bcrypt = require('bcrypt');
4
- const jwt = require('jsonwebtoken');
5
-
6
- // Импортируем проинициализированный объект базы со всеми готовыми моделями
7
- const db = require(path.join(__dirname, '..', 'database', 'config', 'db-init.js'));
8
-
9
- const createMiddleware = require(path.join(__dirname, 'midleware'));
10
- const { MED_PERMISSIONS } = require(path.join(__dirname, 'permissions'));
11
- const AdminService = require(path.join(__dirname, '..', 'database', 'services', 'admin'));
12
- const DoctorService = require(path.join(__dirname, '..', 'database', 'services', 'doctor'));
13
- const PatientService = require(path.join(__dirname, '..', 'database', 'services', 'patient'));
14
-
1
+ const express = require("express");
2
+ const path = require("path");
3
+ const bcrypt = require("bcrypt");
4
+ const jwt = require("jsonwebtoken");
5
+ const db = require(
6
+ path.join(__dirname, "..", "database", "config", "db-init.js"),
7
+ );
8
+ const createMiddleware = require(path.join(__dirname, "midleware"));
9
+ const { MED_PERMISSIONS } = require(path.join(__dirname, "permissions"));
10
+ const AdminService = require(
11
+ path.join(__dirname, "..", "database", "services", "admin"),
12
+ );
13
+ const DoctorService = require(
14
+ path.join(__dirname, "..", "database", "services", "doctor"),
15
+ );
16
+ const PatientService = require(
17
+ path.join(__dirname, "..", "database", "services", "patient"),
18
+ );
15
19
  function createMedRouter(jwtSecret) {
16
20
  const api = express.Router();
17
21
  const web = express.Router();
18
-
19
- // Достаем готовые к работе модели из объекта db
20
- const { User, Disease, Clinic } = db;
21
-
22
+ const { User, Disease, Clinic, Appointment, UserAddress, District, News } =
23
+ db;
22
24
  web.use("/", express.static(path.join(__dirname, "..", "public")));
23
- const { verifyCookie, requireRole, checkPermission } = createMiddleware(jwtSecret);
25
+ const { verifyCookie, requireRole, checkPermission } =
26
+ createMiddleware(jwtSecret);
24
27
 
25
- api.post('/auth/register', async (req, res) => {
28
+ api.post("/auth/register", async (req, res) => {
26
29
  try {
27
30
  const { email, password, fullName } = req.body;
28
- if (!email || !password || !fullName) throw new Error('Заполните обязательные поля: email, password, fullName');
31
+ if (!email || !password || !fullName)
32
+ throw new Error(
33
+ "Заполните обязательные поля: email, password, fullName",
34
+ );
29
35
  const candidate = await User.findOne({ where: { email } });
30
- if (candidate) return res.status(400).json({ success: false, message: 'Email уже занят' });
36
+ if (candidate)
37
+ return res
38
+ .status(400)
39
+ .json({ success: false, message: "Email уже занят" });
31
40
  const hashedPassword = await bcrypt.hash(password, 10);
32
- await User.create({ email, password: hashedPassword, fullName, role: 'patient' });
33
- res.status(201).json({ success: true, message: 'Регистрация успешна' });
41
+ await User.create({
42
+ email,
43
+ password: hashedPassword,
44
+ fullName,
45
+ role: "patient",
46
+ });
47
+ res.status(201).json({ success: true, message: "Регистрация успешна" });
34
48
  } catch (err) {
35
49
  res.status(400).json({ success: false, error: err.message });
36
50
  }
37
51
  });
38
52
 
39
- api.post('/auth/login', async (req, res) => {
53
+ api.post("/auth/login", async (req, res) => {
40
54
  try {
41
55
  const { email, password } = req.body;
42
56
  const user = await User.findOne({ where: { email } });
43
57
  if (!user || !(await bcrypt.compare(password, user.password))) {
44
- return res.status(400).json({ success: false, message: 'Неверный логин или пароль' });
58
+ return res
59
+ .status(400)
60
+ .json({ success: false, message: "Неверный логин или пароль" });
45
61
  }
46
62
  const token = jwt.sign(
47
63
  { id: user.id, role: user.role, specialty: user.specialty },
48
64
  jwtSecret,
49
- { expiresIn: '7d' }
65
+ { expiresIn: "7d" },
50
66
  );
51
- res.cookie('med_auth_token', token, {
67
+ res.cookie("med_auth_token", token, {
52
68
  httpOnly: true,
53
- secure: process.env.NODE_ENV === 'production',
69
+ secure: process.env.NODE_ENV === "production",
54
70
  maxAge: 7 * 24 * 60 * 60 * 1000,
55
- sameSite: 'lax'
71
+ sameSite: "lax",
72
+ });
73
+ res.json({
74
+ success: true,
75
+ user: { id: user.id, fullName: user.fullName, role: user.role },
56
76
  });
57
- res.json({ success: true, user: { id: user.id, fullName: user.fullName, role: user.role } });
58
77
  } catch (err) {
59
78
  res.status(500).json({ success: false, error: err.message });
60
79
  }
61
80
  });
62
81
 
63
- api.post('/auth/logout', (req, res) => {
64
- res.clearCookie('med_auth_token');
65
- res.json({ success: true, message: 'Успешный выход' });
66
- });
67
-
68
- web.get('/med-patient', verifyCookie, requireRole(['patient']), (req, res) => {
69
- res.sendFile(path.join(__dirname, '..', 'public', 'html', 'dashboard-patient.html'));
82
+ api.post("/auth/logout", (req, res) => {
83
+ res.clearCookie("med_auth_token");
84
+ res.json({ success: true, message: "Успешный выход" });
70
85
  });
71
86
 
72
- api.get('/patient/me', verifyCookie, async (req, res) => {
87
+ web.get(
88
+ "/med-patient",
89
+ verifyCookie,
90
+ requireRole(["patient"]),
91
+ (req, res) => {
92
+ res.sendFile(
93
+ path.join(__dirname, "..", "public", "html", "dashboard-patient.html"),
94
+ );
95
+ },
96
+ );
97
+ api.get("/patient/me", verifyCookie, async (req, res) => {
73
98
  try {
74
99
  const fullData = await PatientService.getFullMyData(req.user.id);
75
100
  res.json({ success: true, data: fullData });
@@ -77,188 +102,504 @@ function createMedRouter(jwtSecret) {
77
102
  res.status(500).json({ success: false, error: err.message });
78
103
  }
79
104
  });
80
-
81
- api.post('/patient/address', verifyCookie, async (req, res) => {
105
+ api.post("/patient/address", verifyCookie, async (req, res) => {
82
106
  try {
83
- const updatedAddress = await PatientService.savePatientAddress(req.user.id, req.body);
107
+ const updatedAddress = await PatientService.savePatientAddress(
108
+ req.user.id,
109
+ req.body,
110
+ );
84
111
  res.json({ success: true, address: updatedAddress });
85
112
  } catch (err) {
86
113
  res.status(400).json({ success: false, error: err.message });
87
114
  }
88
115
  });
89
116
 
90
- web.get('/med-doctor', verifyCookie, requireRole(['doctor']), (req, res) => {
91
- res.sendFile(path.join(__dirname, '..', 'public', 'html', 'dashboard-doctor.html'));
117
+ web.get("/med-doctor", verifyCookie, requireRole(["doctor"]), (req, res) => {
118
+ res.sendFile(
119
+ path.join(__dirname, "..", "public", "html", "dashboard-doctor.html"),
120
+ );
92
121
  });
93
122
 
94
- api.get('/doctor/schedule', verifyCookie, requireRole(['doctor']), async (req, res) => {
95
- try {
96
- const schedule = await DoctorService.getMySchedule(req.user.id);
97
- res.json({ success: true, schedule });
98
- } catch (err) {
99
- res.status(500).json({ success: false, error: err.message });
100
- }
101
- });
123
+ api.get(
124
+ "/doctor/schedule",
125
+ verifyCookie,
126
+ requireRole(["doctor"]),
127
+ async (req, res) => {
128
+ try {
129
+ const schedule = await DoctorService.getMySchedule(req.user.id);
130
+ res.json({ success: true, schedule });
131
+ } catch (err) {
132
+ res.status(500).json({ success: false, error: err.message });
133
+ }
134
+ },
135
+ );
102
136
 
103
- api.get('/doctor/patient-history/:id', verifyCookie, requireRole(['doctor']), async (req, res) => {
104
- try {
105
- const history = await DoctorService.getPatientHistory(req.params.id);
106
- res.json({ success: true, history });
107
- } catch (err) {
108
- res.status(404).json({ success: false, error: err.message });
109
- }
110
- });
137
+ api.get(
138
+ "/doctor/patient-history/:id",
139
+ verifyCookie,
140
+ requireRole(["doctor"]),
141
+ async (req, res) => {
142
+ try {
143
+ const history = await DoctorService.getPatientHistory(req.params.id);
144
+ res.json({ success: true, history });
145
+ } catch (err) {
146
+ res.status(404).json({ success: false, error: err.message });
147
+ }
148
+ },
149
+ );
111
150
 
112
- api.post('/doctor/complete-examination', verifyCookie, requireRole(['doctor']), async (req, res) => {
113
- try {
114
- const result = await DoctorService.saveExamination(req.body);
115
- res.json({ success: true, appointment: result });
116
- } catch (err) {
117
- res.status(400).json({ success: false, error: err.message });
118
- }
119
- });
151
+ api.post(
152
+ "/doctor/complete-examination",
153
+ verifyCookie,
154
+ requireRole(["doctor"]),
155
+ async (req, res) => {
156
+ try {
157
+ const result = await DoctorService.saveExamination(req.body);
158
+ res.json({ success: true, appointment: result });
159
+ } catch (err) {
160
+ res.status(400).json({ success: false, error: err.message });
161
+ }
162
+ },
163
+ );
120
164
 
121
- api.post('/doctor/schedule-surgery', verifyCookie, requireRole(['doctor']), checkPermission(MED_PERMISSIONS.SCHEDULE_SURGERY), (req, res) => {
122
- res.json({ success: true, message: 'Операция успешно добавлена в график хирургического отделения.' });
123
- });
165
+ api.post(
166
+ "/doctor/schedule-surgery",
167
+ verifyCookie,
168
+ requireRole(["doctor"]),
169
+ checkPermission(MED_PERMISSIONS.SCHEDULE_SURGERY),
170
+ (req, res) => {
171
+ res.json({
172
+ success: true,
173
+ message:
174
+ "Операция успешно добавлена в график хирургического отделения.",
175
+ });
176
+ },
177
+ );
124
178
 
125
- web.get('/med-admin', verifyCookie, requireRole(['admin']), (req, res) => {
126
- res.sendFile(path.join(__dirname, '..', 'public', 'html', 'dashboard-admin.html'));
179
+ web.get("/med-admin", verifyCookie, requireRole(["admin"]), (req, res) => {
180
+ res.sendFile(
181
+ path.join(__dirname, "..", "public", "html", "dashboard-admin.html"),
182
+ );
127
183
  });
128
184
 
129
- api.post('/admin/clinics', verifyCookie, requireRole(['admin']), async (req, res) => {
130
- try {
131
- const newClinic = await AdminService.createClinic(req.body);
132
- res.status(201).json({ success: true, data: newClinic });
133
- } catch (err) {
134
- res.status(400).json({ success: false, error: err.message });
135
- }
136
- });
137
-
138
- api.post('/admin/staff', verifyCookie, requireRole(['admin']), async (req, res) => {
139
- try {
140
- if (req.body.clinicId && !req.body.ClinicId) {
141
- req.body.ClinicId = req.body.clinicId;
185
+ api.post(
186
+ "/admin/clinics",
187
+ verifyCookie,
188
+ requireRole(["admin"]),
189
+ async (req, res) => {
190
+ try {
191
+ const newClinic = await AdminService.createClinic(req.body);
192
+ res.status(201).json({ success: true, data: newClinic });
193
+ } catch (err) {
194
+ res.status(400).json({ success: false, error: err.message });
142
195
  }
143
- const staffUser = await AdminService.createStaffAccount(req.body);
144
- res.status(201).json({ success: true, data: staffUser });
145
- } catch (err) {
146
- res.status(400).json({ success: false, error: err.message });
147
- }
148
- });
196
+ },
197
+ );
149
198
 
150
- api.delete('/admin/users/:id', verifyCookie, requireRole(['admin']), async (req, res) => {
151
- try {
152
- const result = await AdminService.deleteAccount(req.params.id);
153
- res.json(result);
154
- } catch (err) {
155
- res.status(400).json({ success: false, error: err.message });
156
- }
157
- });
199
+ api.post(
200
+ "/admin/staff",
201
+ verifyCookie,
202
+ requireRole(["admin"]),
203
+ async (req, res) => {
204
+ try {
205
+ if (req.body.clinicId && !req.body.ClinicId) {
206
+ req.body.ClinicId = req.body.clinicId;
207
+ }
208
+ const staffUser = await AdminService.createStaffAccount(req.body);
209
+ res.status(201).json({ success: true, data: staffUser });
210
+ } catch (err) {
211
+ res.status(400).json({ success: false, error: err.message });
212
+ }
213
+ },
214
+ );
158
215
 
159
- api.get('/admin/stats', verifyCookie, requireRole(['admin']), async (req, res) => {
160
- try {
161
- const stats = await AdminService.getSystemStats();
162
- res.json({ success: true, stats });
163
- } catch (err) {
164
- res.status(500).json({ success: false, error: err.message });
165
- }
166
- });
216
+ api.delete(
217
+ "/admin/users/:id",
218
+ verifyCookie,
219
+ requireRole(["admin"]),
220
+ async (req, res) => {
221
+ try {
222
+ const result = await AdminService.deleteAccount(req.params.id);
223
+ res.json(result);
224
+ } catch (err) {
225
+ res.status(400).json({ success: false, error: err.message });
226
+ }
227
+ },
228
+ );
167
229
 
168
- api.get('/admin/list-clinics', verifyCookie, requireRole(['admin']), async (req, res) => {
169
- try {
170
- // ИСПРАВЛЕНИЕ: берем Clinic из инстанса базы данных, а не сырой файл функции
171
- const clinics = await Clinic.findAll({ order: [['name', 'ASC']] });
172
- res.json({ success: true, data: clinics });
173
- } catch (err) {
174
- res.status(500).json({ success: false, error: err.message });
175
- }
176
- });
230
+ api.get(
231
+ "/admin/stats",
232
+ verifyCookie,
233
+ requireRole(["admin"]),
234
+ async (req, res) => {
235
+ try {
236
+ const stats = await AdminService.getSystemStats();
237
+ res.json({ success: true, stats });
238
+ } catch (err) {
239
+ res.status(500).json({ success: false, error: err.message });
240
+ }
241
+ },
242
+ );
243
+ api.get(
244
+ "/admin/list-clinics",
245
+ verifyCookie,
246
+ requireRole(["admin"]),
247
+ async (req, res) => {
248
+ try {
249
+ const clinics = await Clinic.findAll({ order: [["name", "ASC"]] });
250
+ res.json({ success: true, data: clinics });
251
+ } catch (err) {
252
+ res.status(500).json({ success: false, error: err.message });
253
+ }
254
+ },
255
+ );
177
256
 
178
- api.get('/admin/list-staff', verifyCookie, requireRole(['admin']), async (req, res) => {
179
- try {
180
- // ИСПРАВЛЕНИЕ: Используем проинициализированные модули для include отношений
181
- const staff = await User.findAll({
182
- where: { role: 'doctor' },
183
- include: [{ model: Clinic, attributes: ['name'] }],
184
- order: [['fullName', 'ASC']]
185
- });
186
- res.json({ success: true, data: staff });
187
- } catch (err) {
188
- res.status(500).json({ success: false, error: err.message });
189
- }
190
- });
257
+ api.get(
258
+ "/admin/list-staff",
259
+ verifyCookie,
260
+ requireRole(["admin"]),
261
+ async (req, res) => {
262
+ try {
263
+ const staff = await User.findAll({
264
+ where: { role: "doctor" },
265
+ include: [{ model: Clinic, attributes: ["name"] }],
266
+ order: [["fullName", "ASC"]],
267
+ });
268
+ res.json({ success: true, data: staff });
269
+ } catch (err) {
270
+ res.status(500).json({ success: false, error: err.message });
271
+ }
272
+ },
273
+ );
191
274
 
192
- api.get('/patient/doctors-list', verifyCookie, requireRole(['patient']), async (req, res) => {
193
- try {
194
- const doctors = await User.findAll({
195
- where: { role: 'doctor' },
196
- attributes: ['id', 'fullName', 'specialty'],
197
- include: [{ model: Clinic, attributes: ['name', 'address'] }]
198
- });
199
- res.json({ success: true, data: doctors });
200
- } catch (err) {
201
- res.status(500).json({ success: false, error: err.message });
202
- }
203
- });
275
+ api.get(
276
+ "/patient/doctors-list",
277
+ verifyCookie,
278
+ requireRole(["patient"]),
279
+ async (req, res) => {
280
+ try {
281
+ const doctors = await User.findAll({
282
+ where: { role: "doctor" },
283
+ attributes: ["id", "fullName", "specialty"],
284
+ include: [{ model: Clinic, attributes: ["name", "address"] }],
285
+ });
286
+ res.json({ success: true, data: doctors });
287
+ } catch (err) {
288
+ res.status(500).json({ success: false, error: err.message });
289
+ }
290
+ },
291
+ );
204
292
 
205
- api.post('/patient/book', verifyCookie, requireRole(['patient']), async (req, res) => {
206
- try {
207
- const patientId = req.user.id;
208
- const appointment = await PatientService.bookAppointment(patientId, req.body);
209
- res.status(212).json({ success: true, data: appointment });
210
- } catch (err) {
211
- res.status(400).json({ success: false, error: err.message });
212
- }
213
- });
293
+ api.post(
294
+ "/patient/book",
295
+ verifyCookie,
296
+ requireRole(["patient"]),
297
+ async (req, res) => {
298
+ try {
299
+ const patientId = req.user.id;
300
+ const appointment = await PatientService.bookAppointment(
301
+ patientId,
302
+ req.body,
303
+ );
304
+ res.status(212).json({ success: true, data: appointment });
305
+ } catch (err) {
306
+ res.status(400).json({ success: false, error: err.message });
307
+ }
308
+ },
309
+ );
214
310
 
215
- api.get('/doctor/diseases-list', verifyCookie, requireRole(['doctor', 'admin']), async (req, res) => {
216
- try {
217
- // ИСПРАВЛЕНИЕ: Используем готовую модель Disease
218
- const diseases = await Disease.findAll({ order: [['name', 'ASC']] });
219
- res.json({ success: true, data: diseases });
220
- } catch (err) {
221
- res.status(500).json({ success: false, error: err.message });
222
- }
223
- });
311
+ api.get(
312
+ "/doctor/diseases-list",
313
+ verifyCookie,
314
+ requireRole(["doctor", "admin"]),
315
+ async (req, res) => {
316
+ try {
317
+ const diseases = await Disease.findAll({ order: [["name", "ASC"]] });
318
+ res.json({ success: true, data: diseases });
319
+ } catch (err) {
320
+ res.status(500).json({ success: false, error: err.message });
321
+ }
322
+ },
323
+ );
224
324
 
225
- api.post('/auth/change-password', verifyCookie, async (req, res) => {
325
+ api.post("/auth/change-password", verifyCookie, async (req, res) => {
226
326
  try {
227
327
  const { oldPassword, newPassword } = req.body;
228
328
  const userId = req.user.id;
229
329
 
230
330
  if (!oldPassword || !newPassword) {
231
- throw new Error('Необходимо указать старый и новый пароли');
331
+ throw new Error("Необходимо указать старый и новый пароли");
232
332
  }
233
333
 
234
334
  const user = await User.findByPk(userId);
235
- if (!user) throw new Error('Пользователь не найден');
335
+ if (!user) throw new Error("Пользователь не найден");
236
336
 
237
337
  const isMatch = await bcrypt.compare(oldPassword, user.password);
238
338
  if (!isMatch) {
239
- return res.status(400).json({ success: false, message: 'Старый пароль введен неверно' });
339
+ return res
340
+ .status(400)
341
+ .json({ success: false, message: "Старый пароль введен неверно" });
240
342
  }
241
343
 
242
344
  const hashedNewPassword = await bcrypt.hash(newPassword, 10);
243
-
345
+
244
346
  await user.update({
245
347
  password: hashedNewPassword,
246
- isTemporaryPassword: false
348
+ isTemporaryPassword: false,
247
349
  });
248
- res.json({ success: true, message: 'Пароль успешно изменен' });
350
+ res.json({ success: true, message: "Пароль успешно изменен" });
249
351
  } catch (err) {
250
352
  res.status(400).json({ success: false, error: err.message });
251
353
  }
252
354
  });
253
355
 
254
- api.get('/doctor/me', verifyCookie, requireRole(['doctor']), async (req, res) => {
356
+ api.get(
357
+ "/doctor/me",
358
+ verifyCookie,
359
+ requireRole(["doctor"]),
360
+ async (req, res) => {
361
+ try {
362
+ // Используем модель User, полученную онлайн из db
363
+ const doctorData = await User.findByPk(req.user.id, {
364
+ attributes: ["fullName", "position", "specialty"],
365
+ });
366
+ res.json({ success: true, doctor: doctorData });
367
+ } catch (err) {
368
+ res.status(500).json({ success: false, error: err.message });
369
+ }
370
+ },
371
+ );
372
+
373
+ // 1. Создать лечебный участок с привязкой к клинике, улице и кабинету (Для админа)
374
+ api.post(
375
+ "/admin/districts",
376
+ verifyCookie,
377
+ requireRole(["admin"]),
378
+ async (req, res) => {
379
+ try {
380
+ const { name, city, street, houses, cabinet, doctorName, clinicId } =
381
+ req.body;
382
+
383
+ if (!name || !city || !street || !cabinet || !clinicId) {
384
+ throw new Error(
385
+ "Заполните обязательные поля: Название, Город, Улица, Кабинет, ID Клиники",
386
+ );
387
+ }
388
+
389
+ const clinicExists = await Clinic.findByPk(clinicId);
390
+ if (!clinicExists)
391
+ throw new Error(
392
+ `Медицинское учреждение с ID №${clinicId} не найдено.`,
393
+ );
394
+
395
+ const newDistrict = await District.create({
396
+ name,
397
+ city,
398
+ street,
399
+ houses,
400
+ cabinet,
401
+ doctorName,
402
+ ClinicId: parseInt(clinicId, 10),
403
+ });
404
+
405
+ res.status(201).json({ success: true, data: newDistrict });
406
+ } catch (err) {
407
+ res.status(400).json({ success: false, error: err.message });
408
+ }
409
+ },
410
+ );
411
+
412
+ api.get(
413
+ "/admin/districts/:clinicId",
414
+ verifyCookie,
415
+ requireRole(["admin"]),
416
+ async (req, res) => {
417
+ try {
418
+ const list = await District.findAll({
419
+ where: { ClinicId: req.params.clinicId },
420
+ order: [["name", "ASC"]],
421
+ });
422
+ res.json({ success: true, data: list });
423
+ } catch (err) {
424
+ res.status(500).json({ success: false, error: err.message });
425
+ }
426
+ },
427
+ );
428
+ api.get("/public/news-list", async (req, res) => {
255
429
  try {
256
- const doctorData = await User.findByPk(req.user.id, { attributes: ['fullName', 'position', 'specialty'] });
257
- res.json({ success: true, doctor: doctorData });
258
- } catch (err) {
259
- res.status(500).json({ success: false, error: err.message });
260
- }
261
- });
262
- return {web:web, api:api};
430
+ const { News } = db;
431
+ const news = await News.findAll({ order: [["createdAt", "DESC"]] });
432
+ res.json({ success: true, data: news });
433
+ } catch (err) {
434
+ res.status(500).json({ success: false, error: err.message });
435
+ }
436
+ });
437
+ api.post(
438
+ "/admin/news",
439
+ verifyCookie,
440
+ requireRole(["admin"]),
441
+ async (req, res) => {
442
+ try {
443
+ const { News } = db;
444
+ const { title, content } = req.body;
445
+ if (!title || !content)
446
+ throw new Error("Заполните заголовок и текст новости");
447
+ const newPost = await News.create({ title, content });
448
+ res.status(201).json({ success: true, data: newPost });
449
+ } catch (err) {
450
+ res.status(400).json({ success: false, error: err.message });
451
+ }
452
+ },
453
+ );
454
+ api.delete(
455
+ "/admin/news/:id",
456
+ verifyCookie,
457
+ requireRole(["admin"]),
458
+ async (req, res) => {
459
+ try {
460
+ const { News } = db;
461
+ await News.destroy({ where: { id: req.params.id } });
462
+ res.json({ success: true, message: "Новость удалена" });
463
+ } catch (err) {
464
+ res.status(400).json({ success: false, error: err.message });
465
+ }
466
+ },
467
+ );
468
+ web.get("/", (req, res) => {
469
+ res.sendFile(path.join(__dirname, "..", "public", "html", "home.html"));
470
+ });
471
+ api.get(
472
+ "/admin/list-districts",
473
+ verifyCookie,
474
+ requireRole(["admin"]),
475
+ async (req, res) => {
476
+ try {
477
+ const { District, Clinic } = db;
478
+ if (!District) {
479
+ throw new Error(
480
+ "Модель District еще не инициализирована в ядре базы данных",
481
+ );
482
+ }
483
+ const list = await District.findAll({
484
+ include: [{ model: Clinic, attributes: ["name"] }],
485
+ order: [["createdAt", "DESC"]],
486
+ });
487
+ res.json({ success: true, data: list });
488
+ } catch (err) {
489
+ res.status(500).json({ success: false, error: err.message });
490
+ }
491
+ },
492
+ );
493
+ api.get("/public/check-district", async (req, res) => {
494
+ try {
495
+ const { clinicId, city, street, house } = req.query;
496
+ const District = db.models.District || db.District;
497
+ if (!District) {
498
+ throw new Error(
499
+ "Модель District еще не инициализирована в ядре базы данных",
500
+ );
501
+ }
502
+ const cleanCity = city ? city.trim().toUpperCase() : "";
503
+ const cleanStreet = street ? street.trim().toUpperCase() : "";
504
+ const cleanHouse = house ? house.trim().toLowerCase() : "";
505
+ if (!cleanCity || !cleanStreet || !cleanHouse) {
506
+ throw new Error(
507
+ "Для проверки необходимо заполнить город, улицу и номер дома",
508
+ );
509
+ }
510
+ const districts = await District.findAll({
511
+ where: db.sequelize.and(
512
+ { ClinicId: parseInt(clinicId, 10) },
513
+ db.sequelize.where(
514
+ db.sequelize.fn("UPPER", db.sequelize.col("city")),
515
+ cleanCity,
516
+ ),
517
+ db.sequelize.where(
518
+ db.sequelize.fn("UPPER", db.sequelize.col("street")),
519
+ cleanStreet,
520
+ ),
521
+ ),
522
+ });
523
+ for (const dist of districts) {
524
+ const dbHouses = dist.houses.trim().toLowerCase();
525
+ if (dbHouses === "все" || dbHouses === "все дома") {
526
+ return res.json({
527
+ success: true,
528
+ data: {
529
+ assignedDistrict: dist.name,
530
+ assignedCabinet: `${dist.cabinet} (Врач: ${dist.doctorName || "Не назначен"})`,
531
+ },
532
+ });
533
+ }
534
+ if (dbHouses.includes("-")) {
535
+ const [min, max] = dbHouses
536
+ .split("-")
537
+ .map((num) => parseInt(num.trim(), 10));
538
+ const userHouseNum = parseInt(cleanHouse, 10);
539
+ if (!isNaN(min) && !isNaN(max) && !isNaN(userHouseNum)) {
540
+ if (userHouseNum >= min && userHouseNum <= max) {
541
+ return res.json({
542
+ success: true,
543
+ data: {
544
+ assignedDistrict: dist.name,
545
+ assignedCabinet: `${dist.cabinet} (Врач: ${dist.doctorName || "Не назначен"})`,
546
+ },
547
+ });
548
+ }
549
+ }
550
+ }
551
+ if (dbHouses === cleanHouse) {
552
+ return res.json({
553
+ success: true,
554
+ data: {
555
+ assignedDistrict: dist.name,
556
+ assignedCabinet: `${dist.cabinet} (Врач: ${dist.doctorName || "Не назначен"})`,
557
+ },
558
+ });
559
+ }
560
+ }
561
+ res.json({
562
+ success: true,
563
+ data: {
564
+ assignedDistrict: "Участок распределения по домам",
565
+ assignedCabinet: "пройдите в регистратуру",
566
+ },
567
+ });
568
+ } catch (err) {
569
+ res.status(500).json({ success: false, error: err.message });
570
+ }
571
+ });
572
+ api.get("/info/contact/", (req, res) => {
573
+ res.json({
574
+ gmail: process.env.ADMIN_GMAIL,
575
+ phone: process.env.ADMIN_PHONE,
576
+ });
577
+ });
578
+ api.get("/home", async (req, res) => {
579
+ res.redirect("/med/html/home.html");
580
+ });
581
+ api.get("/general", async (req, res) => {
582
+ res.redirect("/med/html/home.html");
583
+ });
584
+ api.get("/h", async (req, res) => {
585
+ res.redirect("/med/html/home.html");
586
+ });
587
+ api.get("/главная", async (req, res) => {
588
+ res.redirect("/med/html/home.html");
589
+ });
590
+ api.get("/Главная", async (req, res) => {
591
+ res.redirect("/med/html/home.html");
592
+ });
593
+ api.get("/Home", async (req, res) => {
594
+ res.redirect("/med/html/home.html");
595
+ });
596
+ api.get("/login", async (req, res) => {
597
+ res.redirect("/med/html/login.html");
598
+ });
599
+ api.get("/вход", async (req, res) => {
600
+ res.redirect("/med/html/login.html");
601
+ });
602
+
603
+ return { web: web, api: api };
263
604
  }
264
- module.exports = createMedRouter;
605
+ module.exports = createMedRouter;