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/database/models/users.js
CHANGED
|
@@ -1,35 +1,78 @@
|
|
|
1
1
|
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const User = sequelize.define(
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
const User = sequelize.define(
|
|
3
|
+
"User",
|
|
4
|
+
{
|
|
5
|
+
id: {
|
|
6
|
+
type: DataTypes.INTEGER,
|
|
7
|
+
autoIncrement: true,
|
|
8
|
+
primaryKey: true,
|
|
9
|
+
},
|
|
10
|
+
email: {
|
|
11
|
+
type: DataTypes.STRING,
|
|
12
|
+
allowNull: false,
|
|
13
|
+
unique: true,
|
|
14
|
+
validate: { isEmail: true },
|
|
15
|
+
},
|
|
16
|
+
password: { type: DataTypes.STRING, allowNull: false },
|
|
17
|
+
fullName: { type: DataTypes.STRING, allowNull: false },
|
|
18
|
+
role: {
|
|
19
|
+
type: DataTypes.ENUM("patient", "doctor", "admin"),
|
|
20
|
+
defaultValue: "patient",
|
|
21
|
+
allowNull: false,
|
|
22
|
+
},
|
|
23
|
+
specialty: {
|
|
24
|
+
type: DataTypes.ENUM(
|
|
25
|
+
"Терапевт",
|
|
26
|
+
"Педиатр",
|
|
27
|
+
"Врач общей практики",
|
|
28
|
+
"Кардиолог",
|
|
29
|
+
"Невролог",
|
|
30
|
+
"Эндокринолог",
|
|
31
|
+
"Гастроэнтеролог",
|
|
32
|
+
"Пульмонолог",
|
|
33
|
+
"Нефролог",
|
|
34
|
+
"Ревматолог",
|
|
35
|
+
"Гематолог",
|
|
36
|
+
"Хирург",
|
|
37
|
+
"Травматолог-ортопед",
|
|
38
|
+
"Сосудистый хирург",
|
|
39
|
+
"Нейрохирург",
|
|
40
|
+
"Кардиохирург",
|
|
41
|
+
"Пластический хирург",
|
|
42
|
+
"Офтальмолог",
|
|
43
|
+
"Отоларинголог",
|
|
44
|
+
"Дерматолог",
|
|
45
|
+
"Стоматолог",
|
|
46
|
+
"Гинеколог",
|
|
47
|
+
"Уролог",
|
|
48
|
+
"Онколог",
|
|
49
|
+
"Инфекционист",
|
|
50
|
+
"Аллерголог-иммунолог",
|
|
51
|
+
"Психиатр",
|
|
52
|
+
"Психотерапевт",
|
|
53
|
+
"Нарколог",
|
|
54
|
+
"Анестезиолог-реаниматолог",
|
|
55
|
+
"Рентгенолог",
|
|
56
|
+
"Врач УЗД",
|
|
57
|
+
"Эндоскопист",
|
|
58
|
+
"Патологоанатом",
|
|
59
|
+
),
|
|
60
|
+
allowNull: true,
|
|
61
|
+
},
|
|
62
|
+
isTemporaryPassword: { type: DataTypes.BOOLEAN, defaultValue: false },
|
|
7
63
|
},
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
fullName: { type: DataTypes.STRING, allowNull: false },
|
|
11
|
-
role: { type: DataTypes.ENUM('patient', 'doctor', 'admin'), defaultValue: 'patient', allowNull: false },
|
|
12
|
-
specialty: {
|
|
13
|
-
type: DataTypes.ENUM(
|
|
14
|
-
'Терапевт', 'Педиатр', 'Врач общей практики', 'Кардиолог', 'Невролог',
|
|
15
|
-
'Эндокринолог', 'Гастроэнтеролог', 'Пульмонолог', 'Нефролог', 'Ревматолог',
|
|
16
|
-
'Гематолог', 'Хирург', 'Травматолог-ортопед', 'Сосудистый хирург', 'Нейрохирург',
|
|
17
|
-
'Кардиохирург', 'Пластический хирург', 'Офтальмолог', 'Отоларинголог', 'Дерматолог',
|
|
18
|
-
'Стоматолог', 'Гинеколог', 'Уролог', 'Онколог', 'Инфекционист', 'Аллерголог-иммунолог',
|
|
19
|
-
'Психиатр', 'Психотерапевт', 'Нарколог', 'Анестезиолог-реаниматолог', 'Рентгенолог',
|
|
20
|
-
'Врач УЗД', 'Эндоскопист', 'Патологоанатом'
|
|
21
|
-
),
|
|
22
|
-
allowNull: true
|
|
64
|
+
{
|
|
65
|
+
timestamps: true,
|
|
23
66
|
},
|
|
24
|
-
|
|
25
|
-
}, {
|
|
26
|
-
timestamps: true
|
|
27
|
-
});
|
|
67
|
+
);
|
|
28
68
|
|
|
29
69
|
// Настройка связей пользователя
|
|
30
70
|
User.associate = (models) => {
|
|
31
|
-
User.belongsTo(models.Clinic, {
|
|
32
|
-
|
|
71
|
+
User.belongsTo(models.Clinic, {
|
|
72
|
+
foreignKey: "ClinicId",
|
|
73
|
+
onDelete: "SET NULL",
|
|
74
|
+
});
|
|
75
|
+
User.hasOne(models.UserAddress, { foreignKey: "UserId" });
|
|
33
76
|
};
|
|
34
77
|
|
|
35
78
|
return User;
|
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
|
-
const
|
|
2
|
+
const dbConfig = require(
|
|
3
|
+
path.join(__dirname, "..", "..", "config", "db-init.js"),
|
|
4
|
+
);
|
|
5
|
+
|
|
3
6
|
const createClinic = {
|
|
4
7
|
async create(clinicData) {
|
|
8
|
+
const Clinic = dbConfig.models.Clinic || dbConfig.Clinic;
|
|
5
9
|
const { name, type, address, phone } = clinicData;
|
|
10
|
+
|
|
6
11
|
if (!name || !type || !address) {
|
|
7
|
-
throw new Error(
|
|
12
|
+
throw new Error("Поля name, type и address обязательны для заполнения");
|
|
8
13
|
}
|
|
14
|
+
|
|
9
15
|
const candidate = await Clinic.findOne({ where: { name } });
|
|
10
16
|
if (candidate) {
|
|
11
|
-
throw new Error(
|
|
17
|
+
throw new Error(
|
|
18
|
+
"Медицинское учреждение с таким названием уже зарегистрировано",
|
|
19
|
+
);
|
|
12
20
|
}
|
|
21
|
+
|
|
13
22
|
return await Clinic.create({ name, type, address, phone });
|
|
14
23
|
},
|
|
24
|
+
|
|
15
25
|
async getAll() {
|
|
16
|
-
|
|
17
|
-
|
|
26
|
+
const Clinic = dbConfig.models.Clinic || dbConfig.Clinic;
|
|
27
|
+
return await Clinic.findAll({ order: [["name", "ASC"]] });
|
|
28
|
+
},
|
|
18
29
|
};
|
|
19
|
-
|
|
30
|
+
|
|
31
|
+
module.exports = createClinic;
|
|
@@ -1,34 +1,60 @@
|
|
|
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 dbAnalytics = {
|
|
8
|
+
/**
|
|
9
|
+
* Собрать общую медицинскую статистику и данные для дашборда
|
|
10
|
+
*/
|
|
7
11
|
async getStats() {
|
|
12
|
+
// Безопасно достаем проинициализированные фабриками модели онлайн
|
|
13
|
+
const Clinic = dbConfig.models.Clinic || dbConfig.Clinic;
|
|
14
|
+
const User = dbConfig.models.User || dbConfig.User;
|
|
15
|
+
const Disease = dbConfig.models.Disease || dbConfig.Disease;
|
|
16
|
+
const Appointment = dbConfig.models.Appointment || dbConfig.Appointment;
|
|
17
|
+
|
|
18
|
+
if (!Clinic || !User || !Disease || !Appointment) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"Критическая ошибка: Модели базы данных еще не проинициализированы!",
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Собираем агрегированные цифры для карточек админки через Sequelize
|
|
8
25
|
const totalClinics = await Clinic.count();
|
|
9
|
-
const totalPatients = await User.count({ where: { role:
|
|
10
|
-
const totalStaff = await User.count({ where: { role:
|
|
26
|
+
const totalPatients = await User.count({ where: { role: "patient" } });
|
|
27
|
+
const totalStaff = await User.count({ where: { role: "doctor" } });
|
|
11
28
|
const totalAppointments = await Appointment.count();
|
|
29
|
+
|
|
30
|
+
// Топ-5 самых частых болезней по инкрементируемому счетчику
|
|
12
31
|
const topDiseases = await Disease.findAll({
|
|
13
32
|
limit: 5,
|
|
14
|
-
order: [[
|
|
15
|
-
attributes: [
|
|
33
|
+
order: [["casesCount", "DESC"]],
|
|
34
|
+
attributes: ["name", "code", "casesCount"],
|
|
16
35
|
});
|
|
36
|
+
|
|
37
|
+
// Разбивка персонала по специальностям (для графиков или таблиц)
|
|
17
38
|
const staffBySpecialty = await User.findAll({
|
|
18
|
-
where: { role:
|
|
19
|
-
attributes: [
|
|
20
|
-
|
|
39
|
+
where: { role: "doctor" },
|
|
40
|
+
attributes: [
|
|
41
|
+
"specialty",
|
|
42
|
+
[User.sequelize.fn("COUNT", User.sequelize.col("id")), "count"],
|
|
43
|
+
],
|
|
44
|
+
group: ["specialty"],
|
|
21
45
|
});
|
|
46
|
+
|
|
22
47
|
return {
|
|
23
48
|
summary: {
|
|
24
49
|
totalClinics,
|
|
25
50
|
totalPatients,
|
|
26
51
|
totalStaff,
|
|
27
|
-
totalAppointments
|
|
52
|
+
totalAppointments,
|
|
28
53
|
},
|
|
29
54
|
topDiseases,
|
|
30
|
-
staffBySpecialty
|
|
55
|
+
staffBySpecialty,
|
|
31
56
|
};
|
|
32
|
-
}
|
|
57
|
+
},
|
|
33
58
|
};
|
|
34
|
-
|
|
59
|
+
|
|
60
|
+
module.exports = dbAnalytics;
|
|
@@ -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;
|