med-cms 1.1.0 → 1.2.1

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # MED-CMS (v1.1.0)
1
+ # MED-CMS (v1.2.0)
2
2
 
3
3
  > ## `med-cms` — Это автономный медецинский движок для управления сетями клиник, персоналом и расписание приймов и т.д. Написан `med-cms` на node.js с использованием **express**, **sequelize**
4
4
 
@@ -19,6 +19,7 @@
19
19
  - **Статистика болезней и МКБ-10:** Выделенный независимый справочник заболеваний в базе данных с возможностью автономной миграции и автоматическим инкрементом счетчиков заболеваемости при закрытии приемов врачами.
20
20
  - **Возможность управлять новостями** А админ панеле есть форма позволяющая выкладывать новости.
21
21
  - **Автозапись в `.env`** При запуске проекта код проверяет есть ли `.env` и настройки в нём, если то записывает настройки в него.
22
+ - **Автопроверка значений** Если вы не изменили значение в `.env` с по умолчанию то ваша консль будет заспамлена
22
23
 
23
24
  ---
24
25
 
package/check_env.js ADDED
@@ -0,0 +1,39 @@
1
+ const print = require("custom-color-logs").print;
2
+
3
+ (function enforceEnvSecurity() {
4
+ const isDefaultJWT = process.env.JWT_SECRET === "0000";
5
+ const isDefaultPass = process.env.ADMIN_PASSWORD === "1234";
6
+
7
+ if (isDefaultJWT || isDefaultPass) {
8
+ // Красивое стартовое предупреждение
9
+ console.log(
10
+ print.ServerMedSeqError(
11
+ "======================================================",
12
+ ),
13
+ );
14
+ console.log(print.ServerMedSeqWarn("ОБНАРУЖЕНЫ НАСТРОЙКИ ПО УМОЛЧАНИЮ!"));
15
+ console.log(
16
+ print.ServerMedSeqWarn(
17
+ "Безопасность системы под угрозой. Данные пациентов уязвимы.",
18
+ ),
19
+ );
20
+ console.log(
21
+ print.ServerMedSeqInfo(
22
+ "Пожалуйста, измените значения JWT_SECRET и ADMIN_PASSWORD в .env",
23
+ ),
24
+ );
25
+ console.log(
26
+ print.ServerMedSeqError(
27
+ "======================================================",
28
+ ),
29
+ );
30
+ const alertInterval = setInterval(() => {
31
+ console.log(
32
+ print.ServerMedSeqError(
33
+ "СРОЧНО СМЕНИТЕ ДЕФОЛТНЫЕ ДАННЫЕ В .env ДЛЯ БЕЗОПАСНОСТИ!",
34
+ ),
35
+ );
36
+ }, 4000);
37
+ alertInterval.unref();
38
+ }
39
+ })();
package/env_init.js CHANGED
@@ -7,7 +7,7 @@ const defaultEnvContent = `
7
7
 
8
8
 
9
9
  # ==============================================================================
10
- # MED-CMS (v1.0.0)
10
+ # MED-CMS (v1.2.0)
11
11
  # ==============================================================================
12
12
 
13
13
  # Специяльный тег инициализации (значение не меняйте)
@@ -15,18 +15,18 @@ MED_CMS_INITIALIZED = true
15
15
 
16
16
 
17
17
  # Код который будет хешироваться в куки
18
- JWT_SECRET = 0000
18
+ JWT_SECRET = "0000"
19
19
 
20
20
 
21
21
  # Данные админа
22
22
  # Почта админестратора
23
- ADMIN_GMAIL = x@gmail.com
23
+ ADMIN_GMAIL = "x@gmail.com"
24
24
 
25
25
  # Телефон админестратора
26
- ADMIN_PHONE = +375 00 00000000
26
+ ADMIN_PHONE = "+375 00 00000000"
27
27
 
28
28
  # Пароль аккаунта админестратора
29
- ADMIN_PASSWORD = 1234
29
+ ADMIN_PASSWORD = "1234"
30
30
  `;
31
31
 
32
32
  function initializeEnvironment() {
package/index.js CHANGED
@@ -6,6 +6,7 @@ const logger = require("custom-color-logs").print;
6
6
  const path = require("path");
7
7
  const fs = require("fs");
8
8
  require(path.join(__dirname, "env_init.js"));
9
+
9
10
  // Оставляем только импорт самого модуля базы данных
10
11
  const dbConfig = require(
11
12
  path.join(__dirname, "database", "config", "db-init.js"),
@@ -97,6 +98,8 @@ async function init(app) {
97
98
  rout.use("/med", r_web);
98
99
  rout.use("/med/api", r_api);
99
100
  app.use("/", rout);
101
+ console.log(logger.ServerMedInfo("Роуты подключены"));
102
+ require(path.join(__dirname, "check_env.js"));
100
103
  }
101
104
 
102
105
  module.exports = init;
package/package.json CHANGED
@@ -1,15 +1,27 @@
1
1
  {
2
2
  "name": "med-cms",
3
- "version": "1.1.0",
4
- "description": "Медицинская мультитендантная CMS на Express и Sequelize (SQLite3) с системой ролей и автоматическим расчетом участков",
3
+ "version": "1.2.1",
4
+ "description": "Медицинская мультитендантная CMS на Express и Sequelize (SQLite3) с системой ролей и автоматическим расчетом участков, а также защитой данных",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
8
8
  "test": "node test.js"
9
9
  },
10
10
  "keywords": [
11
- "medical",
11
+ "med-cms",
12
12
  "cms",
13
+ "medical-engine",
14
+ "clinic-management",
15
+ "hospital-system",
16
+ "arm-doctor",
17
+ "patient-cabinet",
18
+ "miz-by",
19
+ "mkb-10",
20
+ "express-cms",
21
+ "sequelize-cms",
22
+ "sqlite3-autonomous",
23
+ "autonomous-engine",
24
+ "medical",
13
25
  "express",
14
26
  "sequelize",
15
27
  "sqlite3",
@@ -11,7 +11,11 @@ document.addEventListener("DOMContentLoaded", async () => {
11
11
  // Базовая статистика верхних карточек
12
12
  async function loadDashboardStats() {
13
13
  try {
14
- const response = await fetch("/med/api/admin/stats");
14
+ const response = await fetch("/med/api/admin/stats", {
15
+ headers: {
16
+ "Bypass-Tunnel-Reminder": "true",
17
+ },
18
+ });
15
19
  const result = await response.json();
16
20
  if (!result.success) {
17
21
  alert("Ошибка доступа к админ-панели: " + result.message);
@@ -32,7 +36,11 @@ async function loadDashboardStats() {
32
36
  // Загрузка клиник в форму №2 (Создание сотрудника)
33
37
  async function loadClinicsDropdown() {
34
38
  try {
35
- const response = await fetch("/med/api/admin/list-clinics");
39
+ const response = await fetch("/med/api/admin/list-clinics", {
40
+ headers: {
41
+ "Bypass-Tunnel-Reminder": "true",
42
+ },
43
+ });
36
44
  const result = await response.json();
37
45
  const select = document.getElementById("staffClinic");
38
46
  if (!select) return;
@@ -56,7 +64,11 @@ async function loadClinicsForDistrictsSelect() {
56
64
  const select = document.getElementById("distClinicId");
57
65
  if (!select) return;
58
66
  try {
59
- const response = await fetch("/med/api/admin/list-clinics");
67
+ const response = await fetch("/med/api/admin/list-clinics", {
68
+ headers: {
69
+ "Bypass-Tunnel-Reminder": "true",
70
+ },
71
+ });
60
72
  const result = await response.json();
61
73
  select.innerHTML =
62
74
  '<option value="">-- Выберите медицинское учреждение --</option>';
@@ -81,7 +93,11 @@ async function loadStaffForDistrictsSelect() {
81
93
  const select = document.getElementById("distDoctor");
82
94
  if (!select) return;
83
95
  try {
84
- const response = await fetch("/med/api/admin/list-staff");
96
+ const response = await fetch("/med/api/admin/list-staff", {
97
+ headers: {
98
+ "Bypass-Tunnel-Reminder": "true",
99
+ },
100
+ });
85
101
  const result = await response.json();
86
102
  select.innerHTML =
87
103
  '<option value="">-- Выберите сотрудника из базы данных --</option>';
@@ -110,7 +126,11 @@ async function renderLiveDistrictsTable() {
110
126
  const container = document.getElementById("liveDistrictsTableBox");
111
127
  if (!container) return;
112
128
  try {
113
- const res = await fetch("/med/api/admin/list-districts");
129
+ const res = await fetch("/med/api/admin/list-districts", {
130
+ headers: {
131
+ "Bypass-Tunnel-Reminder": "true",
132
+ },
133
+ });
114
134
  const result = await res.json();
115
135
  if (result.success && result.data && result.data.length > 0) {
116
136
  let html = `
@@ -168,6 +188,7 @@ document.getElementById("clinicForm").addEventListener("submit", async (e) => {
168
188
  method: "POST",
169
189
  headers: {
170
190
  "Content-Type": "application/json",
191
+ "Bypass-Tunnel-Reminder": "true",
171
192
  },
172
193
  body: JSON.stringify(payload),
173
194
  });
@@ -209,7 +230,10 @@ document.getElementById("staffForm").addEventListener("submit", async (e) => {
209
230
  try {
210
231
  const response = await fetch("/med/api/admin/staff", {
211
232
  method: "POST",
212
- headers: { "Content-Type": "application/json" },
233
+ headers: {
234
+ "Content-Type": "application/json",
235
+ "Bypass-Tunnel-Reminder": "true",
236
+ },
213
237
  body: JSON.stringify(payload),
214
238
  });
215
239
  const result = await response.json();
@@ -238,7 +262,10 @@ document.getElementById("newsForm").addEventListener("submit", async (e) => {
238
262
  try {
239
263
  const response = await fetch("/med/api/admin/news", {
240
264
  method: "POST",
241
- headers: { "Content-Type": "application/json" },
265
+ headers: {
266
+ "Content-Type": "application/json",
267
+ "Bypass-Tunnel-Reminder": "true",
268
+ },
242
269
  body: JSON.stringify(payload),
243
270
  });
244
271
  const result = await response.json();
@@ -273,7 +300,10 @@ document
273
300
  try {
274
301
  const response = await fetch("/med/api/admin/districts", {
275
302
  method: "POST",
276
- headers: { "Content-Type": "application/json" },
303
+ headers: {
304
+ "Content-Type": "application/json",
305
+ "Bypass-Tunnel-Reminder": "true",
306
+ },
277
307
  body: JSON.stringify(payload),
278
308
  });
279
309
  const result = await response.json();
@@ -297,7 +327,11 @@ async function viewClinicsTable() {
297
327
  title.textContent = " 🏥 Реестр медицинских учреждений системы";
298
328
  content.innerHTML = "Загрузка таблицы...";
299
329
  try {
300
- const res = await fetch("/med/api/admin/list-clinics");
330
+ const res = await fetch("/med/api/admin/list-clinics", {
331
+ headers: {
332
+ "Bypass-Tunnel-Reminder": "true",
333
+ },
334
+ });
301
335
  const result = await res.json();
302
336
  if (result.success && result.data.length > 0) {
303
337
  let html =
@@ -322,7 +356,11 @@ async function viewStaffTable() {
322
356
  title.textContent = "👨‍⚕️ Зарегистрированный медицинский персонал";
323
357
  content.innerHTML = "Загрузка таблицы...";
324
358
  try {
325
- const res = await fetch("/med/api/admin/list-staff");
359
+ const res = await fetch("/med/api/admin/list-staff", {
360
+ headers: {
361
+ "Bypass-Tunnel-Reminder": "true",
362
+ },
363
+ });
326
364
  const result = await res.json();
327
365
  if (result.success && result.data.length > 0) {
328
366
  let html = `<table><thead><tr><th>ID Сотрудника</th><th>ФИО</th><th>Email</th><th>Должность</th><th>Специализация</th><th>Место работы</th></tr></thead><tbody>`;
@@ -358,6 +396,11 @@ async function viewStaffTable() {
358
396
  }
359
397
  }
360
398
  async function logout() {
361
- await fetch("/med/api/auth/logout", { method: "POST" });
362
- window.location.href = "/med/med-login";
399
+ await fetch("/med/api/auth/logout", {
400
+ method: "POST",
401
+ headers: {
402
+ "Bypass-Tunnel-Reminder": "true",
403
+ },
404
+ });
405
+ window.location.href = "/med/html/login.html";
363
406
  }
package/public/js/auth.js CHANGED
@@ -11,7 +11,10 @@ document.getElementById("loginForm").addEventListener("submit", async (e) => {
11
11
  try {
12
12
  const response = await fetch("/med/api/auth/login", {
13
13
  method: "POST",
14
- headers: { "Content-Type": "application/json" },
14
+ headers: {
15
+ "Content-Type": "application/json",
16
+ "Bypass-Tunnel-Reminder": "true",
17
+ },
15
18
  body: JSON.stringify({ email, password }),
16
19
  });
17
20
 
@@ -42,7 +45,10 @@ document
42
45
  try {
43
46
  const response = await fetch("/med/api/auth/register", {
44
47
  method: "POST",
45
- headers: { "Content-Type": "application/json" },
48
+ headers: {
49
+ "Content-Type": "application/json",
50
+ "Bypass-Tunnel-Reminder": "true",
51
+ },
46
52
  body: JSON.stringify({ email, password, fullName }),
47
53
  });
48
54
 
@@ -3,17 +3,17 @@ document.addEventListener("DOMContentLoaded", () => {
3
3
  loadDiseasesCatalog();
4
4
  loadDoctorProfile();
5
5
  });
6
-
7
6
  async function loadDiseasesCatalog() {
8
7
  try {
9
- const res = await fetch("/med/api/doctor/diseases-list");
8
+ const res = await fetch("/med/api/doctor/diseases-list", {
9
+ headers: {
10
+ "Bypass-Tunnel-Reminder": "true",
11
+ },
12
+ });
10
13
  const result = await res.json();
11
-
12
14
  const select = document.getElementById("examDisease");
13
-
14
15
  select.innerHTML =
15
16
  '<option value="">-- Выберите диагноз из справочника МКБ --</option>';
16
-
17
17
  if (result.success && result.data.length > 0) {
18
18
  result.data.forEach((disease) => {
19
19
  const opt = document.createElement("option");
@@ -32,15 +32,16 @@ async function loadDiseasesCatalog() {
32
32
  console.error("❌ Ошибка при получении справочника болезней:", err);
33
33
  }
34
34
  }
35
-
36
35
  async function loadSchedule() {
37
36
  try {
38
- const res = await fetch("/med/api/doctor/schedule");
37
+ const res = await fetch("/med/api/doctor/schedule", {
38
+ headers: {
39
+ "Bypass-Tunnel-Reminder": "true",
40
+ },
41
+ });
39
42
  const data = await res.json();
40
-
41
43
  const list = document.getElementById("scheduleList");
42
44
  list.innerHTML = "";
43
-
44
45
  if (data.success && data.schedule && data.schedule.length > 0) {
45
46
  data.schedule.forEach((ap) => {
46
47
  const li = document.createElement("li");
@@ -55,12 +56,9 @@ async function loadSchedule() {
55
56
  console.error("Ошибка загрузки расписания:", err);
56
57
  }
57
58
  }
58
-
59
59
  document.getElementById("examForm").addEventListener("submit", async (e) => {
60
60
  e.preventDefault();
61
-
62
61
  const selectedDiseaseId = document.getElementById("examDisease").value;
63
-
64
62
  const payload = {
65
63
  appointmentId: document.getElementById("activeAppointmentId").value,
66
64
  complaints: document.getElementById("examComplaints").value,
@@ -68,14 +66,15 @@ document.getElementById("examForm").addEventListener("submit", async (e) => {
68
66
  doctorNotes: document.getElementById("examNotes").value,
69
67
  diseaseId: selectedDiseaseId ? parseInt(selectedDiseaseId, 10) : null,
70
68
  };
71
-
72
69
  try {
73
70
  const res = await fetch("/med/api/doctor/complete-examination", {
74
71
  method: "POST",
75
- headers: { "Content-Type": "application/json" },
72
+ headers: {
73
+ "Content-Type": "application/json",
74
+ "Bypass-Tunnel-Reminder": "true",
75
+ },
76
76
  body: JSON.stringify(payload),
77
77
  });
78
-
79
78
  const result = await res.json();
80
79
  if (result.success) {
81
80
  alert(
@@ -91,7 +90,6 @@ document.getElementById("examForm").addEventListener("submit", async (e) => {
91
90
  alert("Ошибка сети при отправке данных осмотра");
92
91
  }
93
92
  });
94
-
95
93
  function startExamination(appointmentId, patientName) {
96
94
  document.getElementById("examBlock").classList.remove("hidden");
97
95
  document.getElementById("activeAppointmentId").value = appointmentId;
@@ -99,12 +97,21 @@ function startExamination(appointmentId, patientName) {
99
97
  }
100
98
 
101
99
  async function logout() {
102
- await fetch("/med/api/auth/logout", { method: "POST" });
100
+ await fetch("/med/api/auth/logout", {
101
+ method: "POST",
102
+ headers: {
103
+ "Bypass-Tunnel-Reminder": "true",
104
+ },
105
+ });
103
106
  window.location.href = "/med/html/login.html";
104
107
  }
105
108
  async function loadDoctorProfile() {
106
109
  try {
107
- const res = await fetch("/med/api/doctor/me");
110
+ const res = await fetch("/med/api/doctor/me", {
111
+ headers: {
112
+ "Bypass-Tunnel-Reminder": "true",
113
+ },
114
+ });
108
115
  const result = await res.json();
109
116
  if (result.success && result.doctor) {
110
117
  document.getElementById("doctorName").textContent =
@@ -116,28 +123,26 @@ async function loadDoctorProfile() {
116
123
  console.error("Ошибка загрузки профиля сотрудника:", err);
117
124
  }
118
125
  }
119
-
120
126
  function togglePasswordModal() {
121
127
  const modal = document.getElementById("passwordModal");
122
128
  modal.classList.toggle("hidden");
123
129
  document.getElementById("changePasswordForm").reset();
124
130
  }
125
-
126
131
  document
127
132
  .getElementById("changePasswordForm")
128
133
  .addEventListener("submit", async (e) => {
129
134
  e.preventDefault();
130
-
131
135
  const oldPassword = document.getElementById("oldPassword").value;
132
136
  const newPassword = document.getElementById("newPassword").value;
133
-
134
137
  try {
135
138
  const response = await fetch("/med/api/auth/change-password", {
136
139
  method: "POST",
137
- headers: { "Content-Type": "application/json" },
140
+ headers: {
141
+ "Content-Type": "application/json",
142
+ "Bypass-Tunnel-Reminder": "true",
143
+ },
138
144
  body: JSON.stringify({ oldPassword, newPassword }),
139
145
  });
140
-
141
146
  const result = await response.json();
142
147
  if (result.success) {
143
148
  alert("Ваш пароль успешно изменен в базе данных SQLite!");
package/public/js/home.js CHANGED
@@ -1,34 +1,17 @@
1
- // Запуск подгрузки живой ленты новостей при открытии сайта
2
1
  document.addEventListener("DOMContentLoaded", () => {
3
2
  loadLiveNews();
4
3
  });
5
-
6
- // Статические вкладки информационного портала
7
- const staticSections = {
8
- about: {
9
- title: "О нашей клинике",
10
- text: "Мы — современный цифровой медицинский центр РБ, работающий по стандартам автоматизированного распределения пациентов. Наша цель — сделать медицинскую помощь доступной и быстрой.",
11
- },
12
- info: {
13
- title: "Информационный источник",
14
- text: "Полезные статьи о профилактике сезонных ОРВИ, контроле артериального давления при гипертонии и правилах подготовки к плановым диагностическим осмотрам в кабинетах поликлиники.",
15
- },
16
- contacts: {
17
- title: "Контактная информация",
18
- text: "Телефон регистратуры: +375 (17) 000-00-00. Режим работы окон справок: Пн-Пт с 8:00 до 20:00. Адрес: г. Минск, центральный лечебный корпус.",
19
- },
20
- };
21
-
22
- // Динамическое скачивание новостей из SQLite без авторизации
23
4
  async function loadLiveNews() {
24
5
  const box = document.getElementById("news-box");
25
6
  box.innerHTML =
26
7
  '<p style="color: #64748b;">Загрузка свежих новостей клиники...</p>';
27
-
28
8
  try {
29
- const res = await fetch("/med/api/public/news-list");
9
+ const res = await fetch("/med/api/public/news-list", {
10
+ headers: {
11
+ "Bypass-Tunnel-Reminder": "true",
12
+ },
13
+ });
30
14
  const result = await res.json();
31
-
32
15
  if (result.success && result.data.length > 0) {
33
16
  let html = "";
34
17
  result.data.forEach((post) => {
@@ -52,8 +35,6 @@ async function loadLiveNews() {
52
35
  '<p style="color:red;">Не удалось загрузить ленту новостей сервера.</p>';
53
36
  }
54
37
  }
55
-
56
- // Переключатель вкладок навигации по чертежу
57
38
  function switchSection(sectionKey, element) {
58
39
  document
59
40
  .querySelectorAll(".nav-btn")
@@ -63,43 +44,36 @@ function switchSection(sectionKey, element) {
63
44
  news: document.getElementById("news-box"),
64
45
  about: document.getElementById("about-box"),
65
46
  info: document.getElementById("info-box"),
66
- contact: document.getElementById("contacts-box"), // изменил ключ на contact для соответствия строке
47
+ contact: document.getElementById("contacts-box"),
67
48
  };
68
-
69
- // 1. Вызываем функцию для новостей, если выбрана эта секция
70
49
  if (sectionKey === "news" && typeof loadLiveNews === "function") {
71
50
  loadLiveNews();
72
51
  }
73
-
74
- // 2. Скрываем все элементы и показываем только нужный
75
52
  Object.keys(elements).forEach((key) => {
76
53
  if (elements[key]) {
77
- // проверка, что элемент нашелся в DOM
78
54
  elements[key].style.display = key === sectionKey ? "block" : "none";
79
55
  }
80
56
  });
81
57
  }
82
- // Онлайн-проверка лечебного участка по полному адресу кнопкой "ОК"
83
58
  async function checkDistrictOnline() {
84
59
  const city = document.getElementById("checkCityInput").value;
85
60
  const street = document.getElementById("checkStreetInput").value;
86
61
  const house = document.getElementById("checkHouseInput").value;
87
62
  const resultBox = document.getElementById("checkResultBox");
88
-
89
63
  if (!city || !street || !house) {
90
64
  resultBox.innerHTML =
91
65
  '<span style="color:red;">Заполните все три поля: Город, Улица, Дом!</span>';
92
66
  return;
93
67
  }
94
-
95
68
  resultBox.innerHTML = "Проверка адреса в SQLite...";
96
-
97
69
  try {
98
- // Формируем безопасный GET-запрос со всеми параметрами адреса
99
70
  const url = `/med/api/public/check-district?clinicId=1&city=${encodeURIComponent(city)}&street=${encodeURIComponent(street)}&house=${encodeURIComponent(house)}`;
100
- const res = await fetch(url);
71
+ const res = await fetch(url, {
72
+ headers: {
73
+ "Bypass-Tunnel-Reminder": "true",
74
+ },
75
+ });
101
76
  const result = await res.json();
102
-
103
77
  if (result.success) {
104
78
  resultBox.innerHTML = `🩺 ${result.data.assignedDistrict} <br> 🚪 ${result.data.assignedCabinet}`;
105
79
  } else {
@@ -2,26 +2,26 @@ document.addEventListener("DOMContentLoaded", () => {
2
2
  loadPatientData();
3
3
  loadDoctorsForBooking();
4
4
  });
5
-
6
5
  async function loadPatientData() {
7
6
  try {
8
- const response = await fetch("/med/api/patient/me");
7
+ const response = await fetch("/med/api/patient/me", {
8
+ headers: {
9
+ "Bypass-Tunnel-Reminder": "true",
10
+ },
11
+ });
9
12
  const result = await response.json();
10
13
 
11
14
  if (!result.success) {
12
- // ИСПРАВЛЕНИЕ: Читаем result.error (как отдает бэкенд), либо result.message
13
15
  const errorText = result.error || result.message || "Неизвестная ошибка";
14
16
  alert("Ошибка загрузки данных: " + errorText);
15
- window.location.href = "/med/med-login"; // Перенаправляем на правильный веб-роут входа
17
+ window.location.href = "/med/med-login";
16
18
  return;
17
19
  }
18
-
19
20
  const data = result.data;
20
21
  document.getElementById("patientName").textContent =
21
22
  data.personalInfo.fullName;
22
23
  document.getElementById("patientEmail").textContent =
23
24
  data.personalInfo.email;
24
-
25
25
  const districtInfo = document.getElementById("districtInfo");
26
26
  if (data.personalInfo.UserAddress) {
27
27
  const addr = data.personalInfo.UserAddress;
@@ -34,10 +34,8 @@ async function loadPatientData() {
34
34
  document.getElementById("addrStreet").value = addr.street;
35
35
  document.getElementById("addrHouse").value = addr.houseNumber;
36
36
  }
37
-
38
37
  const historyContainer = document.getElementById("medicalHistoryList");
39
38
  historyContainer.innerHTML = "";
40
-
41
39
  if (data.medicalHistory && data.medicalHistory.length > 0) {
42
40
  data.medicalHistory.forEach((record) => {
43
41
  const card = document.createElement("div");
@@ -77,7 +75,6 @@ async function loadPatientData() {
77
75
  alert("Критическая ошибка фронтенда при разборе JSON");
78
76
  }
79
77
  }
80
-
81
78
  document.getElementById("addressForm").addEventListener("submit", async (e) => {
82
79
  e.preventDefault();
83
80
  const payload = {
@@ -88,7 +85,10 @@ document.getElementById("addressForm").addEventListener("submit", async (e) => {
88
85
  try {
89
86
  const response = await fetch("/med/api/patient/address", {
90
87
  method: "POST",
91
- headers: { "Content-Type": "application/json" },
88
+ headers: {
89
+ "Content-Type": "application/json",
90
+ "Bypass-Tunnel-Reminder": "true",
91
+ },
92
92
  body: JSON.stringify(payload),
93
93
  });
94
94
  const result = await response.json();
@@ -104,16 +104,22 @@ document.getElementById("addressForm").addEventListener("submit", async (e) => {
104
104
  alert("Ошибка сети при отправке адреса");
105
105
  }
106
106
  });
107
-
108
107
  async function logout() {
109
- // ИСПРАВЛЕНИЕ: Исправлен путь логаута на абсолютный /med/api
110
- await fetch("/med/api/auth/logout", { method: "POST" });
108
+ await fetch("/med/api/auth/logout", {
109
+ method: "POST",
110
+ headers: {
111
+ "Bypass-Tunnel-Reminder": "true",
112
+ },
113
+ });
111
114
  window.location.href = "/med/med-login";
112
115
  }
113
-
114
116
  async function loadDoctorsForBooking() {
115
117
  try {
116
- const response = await fetch("/med/api/patient/doctors-list");
118
+ const response = await fetch("/med/api/patient/doctors-list", {
119
+ headers: {
120
+ "Bypass-Tunnel-Reminder": "true",
121
+ },
122
+ });
117
123
  const result = await response.json();
118
124
  const select = document.getElementById("bookingDoctor");
119
125
  select.innerHTML = '<option value="">-- Выберите врача --</option>';
@@ -133,7 +139,6 @@ async function loadDoctorsForBooking() {
133
139
  console.error("Ошибка загрузки врачей:", err);
134
140
  }
135
141
  }
136
-
137
142
  document.getElementById("bookingForm").addEventListener("submit", async (e) => {
138
143
  e.preventDefault();
139
144
  const payload = {
@@ -144,7 +149,10 @@ document.getElementById("bookingForm").addEventListener("submit", async (e) => {
144
149
  try {
145
150
  const response = await fetch("/med/api/patient/book", {
146
151
  method: "POST",
147
- headers: { "Content-Type": "application/json" },
152
+ headers: {
153
+ "Content-Type": "application/json",
154
+ "Bypass-Tunnel-Reminder": "true",
155
+ },
148
156
  body: JSON.stringify(payload),
149
157
  });
150
158
  const result = await response.json();