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.
- package/LICENSE.txt +13 -0
- package/README.md +117 -0
- package/database/config/db-init.js +67 -53
- package/database/models/appointments.js +35 -20
- package/database/models/clinics.js +25 -13
- package/database/models/diseases.js +21 -13
- package/database/models/districts.js +55 -0
- package/database/models/news.js +25 -0
- package/database/models/user-addresses.js +21 -14
- package/database/models/users.js +69 -26
- package/database/services/admin/create-clinic.js +18 -6
- package/database/services/admin/db-analytics.js +42 -16
- package/database/services/admin/index.js +6 -6
- package/database/services/admin/manage-staff.js +47 -17
- package/database/services/doctor/conduct-exam.js +26 -20
- package/database/services/doctor/get-schedule.js +26 -18
- package/database/services/doctor/index.js +6 -6
- package/database/services/doctor/patient-access.js +34 -25
- package/database/services/patient/book-appointment.js +37 -17
- package/database/services/patient/calc-district.js +70 -21
- package/database/services/patient/get-profile.js +49 -21
- package/database/services/patient/index.js +5 -5
- package/env_init.js +55 -0
- package/index.d.ts +38 -24
- package/index.js +48 -25
- package/migrate-diseases.js +192 -120
- package/package.json +3 -3
- package/public/css/admin.css +80 -80
- package/public/css/auth.css +52 -44
- package/public/css/doctor.css +131 -125
- package/public/css/home.css +155 -0
- package/public/html/dashboard-admin.html +423 -101
- package/public/html/dashboard-doctor.html +155 -66
- package/public/html/dashboard-patient.html +199 -94
- package/public/html/home/about.html +0 -0
- package/public/html/home/contact.html +0 -0
- package/public/html/home/info.html +0 -0
- package/public/html/home.html +159 -0
- package/public/html/login.html +73 -43
- package/public/js/admin.js +329 -165
- package/public/js/auth.js +45 -41
- package/public/js/doctor.js +117 -103
- package/public/js/home.js +113 -0
- package/public/js/patient.js +130 -108
- package/server/midleware.js +33 -13
- package/server/permissions.js +105 -43
- package/server/server.js +517 -176
- package/README +0 -161
- package/test.js +0 -27
package/server/server.js
CHANGED
|
@@ -1,75 +1,100 @@
|
|
|
1
|
-
const express = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const bcrypt = require(
|
|
4
|
-
const jwt = require(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
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
|
-
|
|
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 } =
|
|
25
|
+
const { verifyCookie, requireRole, checkPermission } =
|
|
26
|
+
createMiddleware(jwtSecret);
|
|
24
27
|
|
|
25
|
-
api.post(
|
|
28
|
+
api.post("/auth/register", async (req, res) => {
|
|
26
29
|
try {
|
|
27
30
|
const { email, password, fullName } = req.body;
|
|
28
|
-
if (!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)
|
|
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({
|
|
33
|
-
|
|
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(
|
|
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
|
|
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:
|
|
65
|
+
{ expiresIn: "7d" },
|
|
50
66
|
);
|
|
51
|
-
res.cookie(
|
|
67
|
+
res.cookie("med_auth_token", token, {
|
|
52
68
|
httpOnly: true,
|
|
53
|
-
secure: process.env.NODE_ENV ===
|
|
69
|
+
secure: process.env.NODE_ENV === "production",
|
|
54
70
|
maxAge: 7 * 24 * 60 * 60 * 1000,
|
|
55
|
-
sameSite:
|
|
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(
|
|
64
|
-
res.clearCookie(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
91
|
-
res.sendFile(
|
|
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(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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(
|
|
122
|
-
|
|
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(
|
|
126
|
-
res.sendFile(
|
|
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(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
} catch (err) {
|
|
146
|
-
res.status(400).json({ success: false, error: err.message });
|
|
147
|
-
}
|
|
148
|
-
});
|
|
196
|
+
},
|
|
197
|
+
);
|
|
149
198
|
|
|
150
|
-
api.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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(
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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(
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
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;
|