med-cms 1.0.0-beta.2 → 1.0.0-beta.5
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/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/index.js +45 -22
- package/migrate-diseases.js +192 -120
- package/package.json +1 -1
- 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 +493 -176
- package/test.js +12 -23
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const createClinic = require(path.join(__dirname,
|
|
3
|
-
const manageStaff = require(path.join(__dirname,
|
|
4
|
-
const dbAnalytics = require(path.join(__dirname,
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const createClinic = require(path.join(__dirname, "create-clinic"));
|
|
3
|
+
const manageStaff = require(path.join(__dirname, "manage-staff"));
|
|
4
|
+
const dbAnalytics = require(path.join(__dirname, "db-analytics"));
|
|
5
5
|
const AdminService = {
|
|
6
6
|
createClinic: createClinic.create,
|
|
7
7
|
getAllClinics: createClinic.getAll,
|
|
8
8
|
createStaffAccount: manageStaff.createAccount,
|
|
9
9
|
deleteAccount: manageStaff.deleteAccount,
|
|
10
|
-
getSystemStats: dbAnalytics.getStats
|
|
10
|
+
getSystemStats: dbAnalytics.getStats,
|
|
11
11
|
};
|
|
12
|
-
module.exports = AdminService;
|
|
12
|
+
module.exports = AdminService;
|
|
@@ -1,41 +1,71 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const dbConfig = require(
|
|
3
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
// ИСПРАВЛЕНИЕ: Добавляем точный импорт вашей библиотеки bcrypt
|
|
7
|
+
const bcrypt = require("bcrypt");
|
|
8
|
+
|
|
5
9
|
const manageStaff = {
|
|
6
|
-
|
|
10
|
+
async createAccount(staffData) {
|
|
11
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
12
|
+
const Clinic = dbConfig.models.Clinic || dbConfig.Clinic;
|
|
13
|
+
|
|
7
14
|
const { email, rawPassword, fullName, medicalProfile } = staffData;
|
|
8
15
|
const ClinicId = staffData.ClinicId || staffData.clinicId;
|
|
16
|
+
|
|
9
17
|
if (!email || !rawPassword || !fullName || !medicalProfile || !ClinicId) {
|
|
10
|
-
throw new Error(
|
|
18
|
+
throw new Error(
|
|
19
|
+
"Необходимо заполнить обязательные поля: email, rawPassword, fullName, medicalProfile, clinicId",
|
|
20
|
+
);
|
|
11
21
|
}
|
|
22
|
+
|
|
12
23
|
const clinicExists = await Clinic.findByPk(ClinicId);
|
|
13
24
|
if (!clinicExists) {
|
|
14
25
|
throw new Error(`Медицинское учреждение с ID №${ClinicId} не найдено.`);
|
|
15
26
|
}
|
|
27
|
+
|
|
16
28
|
const candidate = await User.findOne({ where: { email } });
|
|
17
29
|
if (candidate) {
|
|
18
|
-
throw new Error(
|
|
30
|
+
throw new Error("Сотрудник с таким email уже зарегистрирован");
|
|
19
31
|
}
|
|
20
|
-
|
|
32
|
+
|
|
33
|
+
// Хешируем временный пароль с помощью подключенного нативного bcrypt
|
|
34
|
+
const hashedPassword = await bcrypt.hash(rawPassword, 10);
|
|
35
|
+
|
|
36
|
+
let finalPosition = "Врач";
|
|
21
37
|
let finalSpecialty = medicalProfile;
|
|
22
|
-
const purePositions = [
|
|
38
|
+
const purePositions = [
|
|
39
|
+
"Главврач",
|
|
40
|
+
"Медсестра",
|
|
41
|
+
"Врач скорой помощи",
|
|
42
|
+
"Фельдшер",
|
|
43
|
+
"Регистратор",
|
|
44
|
+
];
|
|
45
|
+
|
|
23
46
|
if (purePositions.includes(medicalProfile)) {
|
|
24
47
|
finalPosition = medicalProfile;
|
|
25
|
-
finalSpecialty =
|
|
48
|
+
finalSpecialty = "Общий медицинский профиль";
|
|
26
49
|
}
|
|
27
|
-
|
|
28
|
-
|
|
50
|
+
|
|
51
|
+
return await User.create({
|
|
29
52
|
email,
|
|
30
53
|
password: hashedPassword,
|
|
31
54
|
fullName,
|
|
32
|
-
role:
|
|
55
|
+
role: "doctor",
|
|
33
56
|
position: finalPosition,
|
|
34
57
|
specialty: finalSpecialty,
|
|
35
58
|
ClinicId: Number(ClinicId),
|
|
36
|
-
isTemporaryPassword: true
|
|
59
|
+
isTemporaryPassword: true,
|
|
37
60
|
});
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
async deleteAccount(userId) {
|
|
64
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
65
|
+
const deletedRows = await User.destroy({ where: { id: userId } });
|
|
66
|
+
if (deletedRows === 0) throw new Error("Аккаунт не найден");
|
|
67
|
+
return { success: true, message: "Аккаунт успешно удален" };
|
|
68
|
+
},
|
|
40
69
|
};
|
|
41
|
-
|
|
70
|
+
|
|
71
|
+
module.exports = manageStaff;
|
|
@@ -1,33 +1,39 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const
|
|
3
|
-
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const dbConfig = require(
|
|
3
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
4
|
+
);
|
|
5
|
+
|
|
4
6
|
const conductExam = {
|
|
5
7
|
async saveResult(examData) {
|
|
6
|
-
const { appointmentId, complaints, objectively, doctorNotes, diseaseId } =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const { appointmentId, complaints, objectively, doctorNotes, diseaseId } =
|
|
9
|
+
examData;
|
|
10
|
+
|
|
11
|
+
const Appointment = dbConfig.models.Appointment || dbConfig.Appointment;
|
|
12
|
+
const Disease = dbConfig.models.Disease || dbConfig.Disease;
|
|
13
|
+
|
|
14
|
+
if (!appointmentId) throw new Error("ID приема обязателен");
|
|
15
|
+
|
|
10
16
|
const appointment = await Appointment.findByPk(appointmentId);
|
|
11
|
-
if (!appointment)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
throw new Error('Этот прием уже был успешно завершен ранее');
|
|
16
|
-
}
|
|
17
|
+
if (!appointment) throw new Error("Прием не найден");
|
|
18
|
+
if (appointment.status === "завершен")
|
|
19
|
+
throw new Error("Прием уже завершен");
|
|
20
|
+
|
|
17
21
|
appointment.complaints = complaints;
|
|
18
22
|
appointment.objectively = objectively;
|
|
19
23
|
appointment.doctorNotes = doctorNotes;
|
|
20
|
-
appointment.status =
|
|
24
|
+
appointment.status = "завершен";
|
|
25
|
+
|
|
21
26
|
if (diseaseId) {
|
|
22
27
|
const disease = await Disease.findByPk(diseaseId);
|
|
23
|
-
if (!disease)
|
|
24
|
-
|
|
25
|
-
}
|
|
28
|
+
if (!disease) throw new Error("Болезнь не найдена в справочнике");
|
|
29
|
+
|
|
26
30
|
appointment.DiseaseId = diseaseId;
|
|
27
|
-
await disease.increment(
|
|
31
|
+
await disease.increment("casesCount", { by: 1 });
|
|
28
32
|
}
|
|
33
|
+
|
|
29
34
|
await appointment.save();
|
|
30
35
|
return appointment;
|
|
31
|
-
}
|
|
36
|
+
},
|
|
32
37
|
};
|
|
33
|
-
|
|
38
|
+
|
|
39
|
+
module.exports = conductExam;
|
|
@@ -1,23 +1,31 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const
|
|
3
|
-
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const dbConfig = require(
|
|
3
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
4
|
+
);
|
|
5
|
+
|
|
4
6
|
const getSchedule = {
|
|
5
7
|
async byDoctorId(doctorId) {
|
|
6
|
-
if (!doctorId)
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
if (!doctorId) throw new Error("ID врача не указан");
|
|
9
|
+
|
|
10
|
+
// Достаем проинициализированные модели из синглтона
|
|
11
|
+
const Appointment = dbConfig.models.Appointment || dbConfig.Appointment;
|
|
12
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
13
|
+
|
|
9
14
|
return await Appointment.findAll({
|
|
10
|
-
where: {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
where: { DoctorId: doctorId, status: "ожидается" },
|
|
16
|
+
include: [
|
|
17
|
+
{
|
|
18
|
+
model: User,
|
|
19
|
+
as: "Patient",
|
|
20
|
+
attributes: ["id", "fullName", "email"],
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
order: [
|
|
24
|
+
["date", "ASC"],
|
|
25
|
+
["time", "ASC"],
|
|
26
|
+
],
|
|
20
27
|
});
|
|
21
|
-
}
|
|
28
|
+
},
|
|
22
29
|
};
|
|
23
|
-
|
|
30
|
+
|
|
31
|
+
module.exports = getSchedule;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const getSchedule = require(path.join(__dirname,
|
|
3
|
-
const patientAccess = require(path.join(__dirname,
|
|
4
|
-
const conductExam = require(path.join(__dirname,
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const getSchedule = require(path.join(__dirname, "get-schedule"));
|
|
3
|
+
const patientAccess = require(path.join(__dirname, "patient-access"));
|
|
4
|
+
const conductExam = require(path.join(__dirname, "conduct-exam"));
|
|
5
5
|
const DoctorService = {
|
|
6
6
|
getMySchedule: getSchedule.byDoctorId,
|
|
7
7
|
getPatientHistory: patientAccess.getHistory,
|
|
8
|
-
saveExamination: conductExam.saveResult
|
|
8
|
+
saveExamination: conductExam.saveResult,
|
|
9
9
|
};
|
|
10
|
-
module.exports = DoctorService;
|
|
10
|
+
module.exports = DoctorService;
|
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
const dbConfig = require(
|
|
3
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
4
|
+
);
|
|
5
|
+
|
|
6
6
|
const patientAccess = {
|
|
7
7
|
async getHistory(patientId) {
|
|
8
|
-
if (!patientId)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
8
|
+
if (!patientId) throw new Error("ID пациента не указан");
|
|
9
|
+
|
|
10
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
11
|
+
const Appointment = dbConfig.models.Appointment || dbConfig.Appointment;
|
|
12
|
+
const Disease = dbConfig.models.Disease || dbConfig.Disease;
|
|
13
|
+
const UserAddress = dbConfig.models.UserAddress || dbConfig.UserAddress;
|
|
14
|
+
|
|
15
|
+
return await User.findByPk(patientId, {
|
|
16
|
+
attributes: ["id", "fullName", "email"],
|
|
13
17
|
include: [
|
|
14
|
-
{
|
|
18
|
+
{
|
|
15
19
|
model: UserAddress,
|
|
16
|
-
attributes: [
|
|
20
|
+
attributes: [
|
|
21
|
+
"city",
|
|
22
|
+
"street",
|
|
23
|
+
"houseNumber",
|
|
24
|
+
"assignedDistrict",
|
|
25
|
+
"assignedCabinet",
|
|
26
|
+
],
|
|
17
27
|
},
|
|
18
|
-
{
|
|
19
|
-
model: Appointment,
|
|
20
|
-
as:
|
|
21
|
-
where: { status:
|
|
22
|
-
include: [{ model: Disease, attributes: [
|
|
23
|
-
required: false
|
|
24
|
-
}
|
|
28
|
+
{
|
|
29
|
+
model: Appointment,
|
|
30
|
+
as: "PatientAppointments",
|
|
31
|
+
where: { status: "завершен" },
|
|
32
|
+
include: [{ model: Disease, attributes: ["name", "code"] }],
|
|
33
|
+
required: false,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
order: [
|
|
37
|
+
[{ model: Appointment, as: "PatientAppointments" }, "date", "DESC"],
|
|
25
38
|
],
|
|
26
|
-
order: [[{ model: Appointment, as: 'PatientAppointments' }, 'date', 'DESC']]
|
|
27
39
|
});
|
|
28
|
-
|
|
29
|
-
throw new Error('Пациент не найден в базе данных');
|
|
30
|
-
}
|
|
31
|
-
return patient;
|
|
32
|
-
}
|
|
40
|
+
},
|
|
33
41
|
};
|
|
34
|
-
|
|
42
|
+
|
|
43
|
+
module.exports = patientAccess;
|
|
@@ -1,45 +1,65 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
const
|
|
3
|
-
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const dbConfig = require(
|
|
3
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
4
|
+
);
|
|
5
|
+
|
|
4
6
|
const bookAppointment = {
|
|
7
|
+
/**
|
|
8
|
+
* Записать пациента к врачу на свободное время
|
|
9
|
+
*/
|
|
5
10
|
async create(patientId, appointmentData) {
|
|
6
11
|
const { doctorId, date, time } = appointmentData;
|
|
12
|
+
|
|
13
|
+
const Appointment = dbConfig.models.Appointment || dbConfig.Appointment;
|
|
14
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
15
|
+
|
|
7
16
|
if (!doctorId || !date || !time) {
|
|
8
|
-
throw new Error(
|
|
17
|
+
throw new Error("Необходимо выбрать врача, дату и время приема");
|
|
9
18
|
}
|
|
10
|
-
|
|
19
|
+
|
|
20
|
+
const doctor = await User.findOne({
|
|
21
|
+
where: { id: doctorId, role: "doctor" },
|
|
22
|
+
});
|
|
11
23
|
if (!doctor) {
|
|
12
|
-
throw new Error(
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Указанный сотрудник не найден или не имеет прав на прием",
|
|
26
|
+
);
|
|
13
27
|
}
|
|
28
|
+
|
|
14
29
|
const isSlotBusy = await Appointment.findOne({
|
|
15
30
|
where: {
|
|
16
31
|
DoctorId: doctorId,
|
|
17
32
|
date: date,
|
|
18
33
|
time: time,
|
|
19
|
-
status:
|
|
20
|
-
}
|
|
34
|
+
status: "ожидается",
|
|
35
|
+
},
|
|
21
36
|
});
|
|
37
|
+
|
|
22
38
|
if (isSlotBusy) {
|
|
23
|
-
throw new Error(`Время ${time} на дату ${date}
|
|
39
|
+
throw new Error(`Время ${time} на дату ${date} уже занято.`);
|
|
24
40
|
}
|
|
41
|
+
|
|
25
42
|
const isPatientDoubleBooked = await Appointment.findOne({
|
|
26
43
|
where: {
|
|
27
44
|
PatientId: patientId,
|
|
28
45
|
DoctorId: doctorId,
|
|
29
46
|
date: date,
|
|
30
|
-
status:
|
|
31
|
-
}
|
|
47
|
+
status: "ожидается",
|
|
48
|
+
},
|
|
32
49
|
});
|
|
50
|
+
|
|
33
51
|
if (isPatientDoubleBooked) {
|
|
34
|
-
throw new Error(`Вы уже записаны к
|
|
52
|
+
throw new Error(`Вы уже записаны к этому специалисту на выбранную дату.`);
|
|
35
53
|
}
|
|
54
|
+
|
|
36
55
|
return await Appointment.create({
|
|
37
56
|
date,
|
|
38
57
|
time,
|
|
39
|
-
status:
|
|
40
|
-
PatientId: patientId,
|
|
41
|
-
DoctorId: doctorId
|
|
58
|
+
status: "ожидается",
|
|
59
|
+
PatientId: Number(patientId),
|
|
60
|
+
DoctorId: Number(doctorId),
|
|
42
61
|
});
|
|
43
|
-
}
|
|
62
|
+
},
|
|
44
63
|
};
|
|
45
|
-
|
|
64
|
+
|
|
65
|
+
module.exports = bookAppointment;
|
|
@@ -1,49 +1,98 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
-
|
|
2
|
+
// Импортируем строго синглтон базы данных для исключения круговой зависимости
|
|
3
|
+
const dbConfig = require(
|
|
4
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
5
|
+
);
|
|
6
|
+
|
|
3
7
|
const calcDistrict = {
|
|
4
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Динамический поиск участка по названию улицы в таблице настроек админа
|
|
10
|
+
*/
|
|
11
|
+
async determineLocation(clinicId, street) {
|
|
5
12
|
const cleanedStreet = street.trim().toLowerCase();
|
|
6
|
-
|
|
13
|
+
|
|
14
|
+
// Достаем проинициализированную модель Участков онлайн
|
|
15
|
+
const District = dbConfig.models.District || dbConfig.District;
|
|
16
|
+
|
|
17
|
+
if (!District) {
|
|
18
|
+
console.log(
|
|
19
|
+
"⚠️ [Med Module] Модель District еще не инициализирована в БД",
|
|
20
|
+
);
|
|
7
21
|
return {
|
|
8
|
-
assignedDistrict:
|
|
9
|
-
assignedCabinet:
|
|
22
|
+
assignedDistrict: "Общий распределительный участок",
|
|
23
|
+
assignedCabinet: "Кабинет №100 (Регистратура)",
|
|
10
24
|
};
|
|
11
25
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
|
|
27
|
+
// Ищем все участки, закрепленные за данной клиникой в SQLite
|
|
28
|
+
const districts = await District.findAll({ where: { ClinicId: clinicId } });
|
|
29
|
+
|
|
30
|
+
// Проверяем, в какой из участков админ записал эту улицу
|
|
31
|
+
for (const district of districts) {
|
|
32
|
+
const streetsArray = district.coveredStreets
|
|
33
|
+
.split(",")
|
|
34
|
+
.map((s) => s.trim());
|
|
35
|
+
|
|
36
|
+
if (streetsArray.includes(cleanedStreet)) {
|
|
37
|
+
return {
|
|
38
|
+
assignedDistrict: district.name,
|
|
39
|
+
assignedCabinet: `${district.cabinet} (Врач: ${district.doctorName || "Не назначен"})`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
17
42
|
}
|
|
43
|
+
|
|
44
|
+
// Дефолтный вариант, если админ еще не добавил эту улицу в карту покрытия
|
|
18
45
|
return {
|
|
19
|
-
assignedDistrict:
|
|
20
|
-
assignedCabinet:
|
|
46
|
+
assignedDistrict: "Общий распределительный участок",
|
|
47
|
+
assignedCabinet: "Кабинет №100 (Регистратура)",
|
|
21
48
|
};
|
|
22
49
|
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Привязка адреса к пациенту с динамическим расчетом участка
|
|
53
|
+
*/
|
|
23
54
|
async saveAddress(userId, addressData) {
|
|
24
|
-
const { city, street, houseNumber } = addressData;
|
|
25
|
-
|
|
26
|
-
|
|
55
|
+
const { city, street, houseNumber, clinicId } = addressData;
|
|
56
|
+
|
|
57
|
+
// Достаем модель адресов из базы
|
|
58
|
+
const UserAddress = dbConfig.models.UserAddress || dbConfig.UserAddress;
|
|
59
|
+
|
|
60
|
+
if (!city || !street || !houseNumber || !clinicId) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"Заполните обязательные поля: город, улица, дом, ID клиники прикрепления",
|
|
63
|
+
);
|
|
27
64
|
}
|
|
28
|
-
|
|
29
|
-
|
|
65
|
+
|
|
66
|
+
// Вычисляем лечебный участок по динамической карте улиц из базы данных
|
|
67
|
+
const { assignedDistrict, assignedCabinet } = await this.determineLocation(
|
|
68
|
+
clinicId,
|
|
69
|
+
street,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Проверяем, обновляет ли пациент старый адрес или создает новый
|
|
73
|
+
const existingAddress = await UserAddress.findOne({
|
|
74
|
+
where: { UserId: userId },
|
|
75
|
+
});
|
|
76
|
+
|
|
30
77
|
if (existingAddress) {
|
|
31
78
|
return await existingAddress.update({
|
|
32
79
|
city,
|
|
33
80
|
street,
|
|
34
81
|
houseNumber,
|
|
35
82
|
assignedDistrict,
|
|
36
|
-
assignedCabinet
|
|
83
|
+
assignedCabinet,
|
|
37
84
|
});
|
|
38
85
|
}
|
|
86
|
+
|
|
39
87
|
return await UserAddress.create({
|
|
40
88
|
UserId: userId,
|
|
41
89
|
city,
|
|
42
90
|
street,
|
|
43
91
|
houseNumber,
|
|
44
92
|
assignedDistrict,
|
|
45
|
-
assignedCabinet
|
|
93
|
+
assignedCabinet,
|
|
46
94
|
});
|
|
47
|
-
}
|
|
95
|
+
},
|
|
48
96
|
};
|
|
49
|
-
|
|
97
|
+
|
|
98
|
+
module.exports = calcDistrict;
|
|
@@ -1,47 +1,75 @@
|
|
|
1
|
-
const path = require("path")
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
const path = require("path");
|
|
2
|
+
// Импортируем синглтон конфигурации базы данных
|
|
3
|
+
const dbConfig = require(
|
|
4
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
5
|
+
);
|
|
6
|
+
|
|
6
7
|
const getProfile = {
|
|
8
|
+
/**
|
|
9
|
+
* Собрать полное медицинское досье пациента для личного кабинета
|
|
10
|
+
*/
|
|
7
11
|
async getFullData(patientId) {
|
|
8
12
|
if (!patientId) {
|
|
9
|
-
throw new Error(
|
|
13
|
+
throw new Error("ID пациента не указан");
|
|
10
14
|
}
|
|
15
|
+
|
|
16
|
+
// Безопасно достаем проинициализированные модели
|
|
17
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
18
|
+
const UserAddress = dbConfig.models.UserAddress || dbConfig.UserAddress;
|
|
19
|
+
const Appointment = dbConfig.models.Appointment || dbConfig.Appointment;
|
|
20
|
+
const Disease = dbConfig.models.Disease || dbConfig.Disease;
|
|
21
|
+
|
|
22
|
+
// 1. Ищем профиль пользователя с адресом
|
|
11
23
|
const profile = await User.findByPk(patientId, {
|
|
12
|
-
attributes: { exclude: [
|
|
24
|
+
attributes: { exclude: ["password"] },
|
|
13
25
|
include: [
|
|
14
26
|
{
|
|
15
27
|
model: UserAddress,
|
|
16
|
-
attributes: [
|
|
17
|
-
|
|
18
|
-
|
|
28
|
+
attributes: [
|
|
29
|
+
"city",
|
|
30
|
+
"street",
|
|
31
|
+
"houseNumber",
|
|
32
|
+
"assignedDistrict",
|
|
33
|
+
"assignedCabinet",
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
],
|
|
19
37
|
});
|
|
38
|
+
|
|
20
39
|
if (!profile) {
|
|
21
|
-
throw new Error(
|
|
40
|
+
throw new Error("Профиль пациента не найден в базе данных");
|
|
22
41
|
}
|
|
42
|
+
|
|
43
|
+
// 2. Находим всю историю приёмов с врачами и диагнозами (используем правильный alias PatientAppointments)
|
|
23
44
|
const appointments = await Appointment.findAll({
|
|
24
45
|
where: { PatientId: patientId },
|
|
25
46
|
include: [
|
|
26
47
|
{
|
|
27
48
|
model: User,
|
|
28
|
-
as:
|
|
29
|
-
attributes: [
|
|
49
|
+
as: "Doctor",
|
|
50
|
+
attributes: ["fullName", "specialty", "position"],
|
|
30
51
|
},
|
|
31
52
|
{
|
|
32
53
|
model: Disease,
|
|
33
|
-
attributes: [
|
|
34
|
-
|
|
54
|
+
attributes: [
|
|
55
|
+
"name",
|
|
56
|
+
"code",
|
|
57
|
+
"treatmentRecommendations",
|
|
58
|
+
"recommendedMedications",
|
|
59
|
+
],
|
|
60
|
+
},
|
|
35
61
|
],
|
|
36
62
|
order: [
|
|
37
|
-
[
|
|
38
|
-
[
|
|
39
|
-
]
|
|
63
|
+
["date", "DESC"],
|
|
64
|
+
["time", "DESC"],
|
|
65
|
+
],
|
|
40
66
|
});
|
|
67
|
+
|
|
41
68
|
return {
|
|
42
69
|
personalInfo: profile,
|
|
43
|
-
medicalHistory: appointments
|
|
70
|
+
medicalHistory: appointments,
|
|
44
71
|
};
|
|
45
|
-
}
|
|
72
|
+
},
|
|
46
73
|
};
|
|
47
|
-
|
|
74
|
+
|
|
75
|
+
module.exports = getProfile;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
-
const calcDistrict = require(path.join(__dirname,
|
|
3
|
-
const getProfile = require(path.join(__dirname,
|
|
4
|
-
const bookAppointment = require(path.join(__dirname,
|
|
2
|
+
const calcDistrict = require(path.join(__dirname, "calc-district"));
|
|
3
|
+
const getProfile = require(path.join(__dirname, "get-profile"));
|
|
4
|
+
const bookAppointment = require(path.join(__dirname, "book-appointment"));
|
|
5
5
|
const PatientService = {
|
|
6
6
|
savePatientAddress: calcDistrict.saveAddress.bind(calcDistrict),
|
|
7
7
|
getFullMyData: getProfile.getFullData,
|
|
8
|
-
bookAppointment: bookAppointment.create.bind(bookAppointment)
|
|
8
|
+
bookAppointment: bookAppointment.create.bind(bookAppointment),
|
|
9
9
|
};
|
|
10
|
-
module.exports = PatientService;
|
|
10
|
+
module.exports = PatientService;
|